CernVM-FS  2.9.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/wait.h>
37 #include <unistd.h>
38 // If valgrind headers are present on the build system, then we can detect
39 // valgrind at runtime.
40 #ifdef HAS_VALGRIND_HEADERS
41 #include <valgrind/valgrind.h>
42 #endif
43 
44 #include <algorithm>
45 #include <cassert>
46 #include <cstdio>
47 #include <cstring>
48 #include <map>
49 #include <set>
50 #include <string>
51 #include <vector>
52 
53 #include "fs_traversal.h"
54 #include "logging.h"
55 #include "platform.h"
56 #include "util/algorithm.h"
57 #include "util/exception.h"
58 #include "util/string.h"
59 #include "util_concurrency.h"
60 
61 //using namespace std; // NOLINT
62 
63 #ifndef ST_RDONLY
64 // On Linux, this is in sys/statvfs.h
65 // On macOS, this flag is called MNT_RDONLY /usr/include/sys/mount.h
66 #define ST_RDONLY 1
67 #endif
68 
69 // Older Linux glibc versions do not provide the f_flags member in struct statfs
70 #define CVMFS_HAS_STATFS_F_FLAGS
71 #ifndef __APPLE__
72 #ifdef __GLIBC_MINOR__
73 #if __GLIBC_MINOR__ < 12
74 #undef CVMFS_HAS_STATFS_F_FLAGS
75 #endif
76 #endif
77 #endif
78 
79 // Work around missing clearenv()
80 #ifdef __APPLE__
81 extern "C" {
82 extern char **environ;
83 }
84 #endif
85 
86 #ifdef CVMFS_NAMESPACE_GUARD
87 namespace CVMFS_NAMESPACE_GUARD {
88 #endif
89 
90 static pthread_mutex_t getumask_mutex = PTHREAD_MUTEX_INITIALIZER;
91 
92 
96 std::string MakeCanonicalPath(const std::string &path) {
97  if (path.length() == 0) return path;
98 
99  if (path[path.length()-1] == '/') {
100  return path.substr(0, path.length()-1);
101  } else {
102  return path;
103  }
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 
145  int length = static_cast<int>(path.GetLength());
146  if (length == 0)
147  return path;
148  const char *chars = path.GetChars();
149 
150  for (int i = length-1; i >= 0; --i) {
151  if (chars[i] == '/')
152  return PathString(chars, i);
153  }
154 
155  return path;
156 }
157 
158 
162 std::string GetFileName(const std::string &path) {
163  const std::string::size_type idx = path.find_last_of('/');
164  if (idx != std::string::npos) {
165  return path.substr(idx+1);
166  } else {
167  return path;
168  }
169 }
170 
171 
173  NameString name;
174  int length = static_cast<int>(path.GetLength());
175  const char *chars = path.GetChars();
176 
177  int i;
178  for (i = length-1; i >= 0; --i) {
179  if (chars[i] == '/')
180  break;
181  }
182  i++;
183  if (i < length) {
184  name.Append(chars+i, length-i);
185  }
186 
187  return name;
188 }
189 
190 
191 bool IsAbsolutePath(const std::string &path) {
192  return (!path.empty() && path[0] == '/');
193 }
194 
195 
196 std::string GetAbsolutePath(const std::string &path) {
197  if (IsAbsolutePath(path))
198  return path;
199 
200  return GetCurrentWorkingDirectory() + "/" + path;
201 }
202 
203 
204 bool IsHttpUrl(const std::string &path) {
205  if (path.length() < 7) {
206  return false;
207  }
208 
209  std::string prefix = path.substr(0, 8);
210  std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
211 
212  return prefix.substr(0, 7) == "http://" || prefix == "https://";
213 }
214 
215 
216 FileSystemInfo GetFileSystemInfo(const std::string &path) {
217  FileSystemInfo result;
218 
219  struct statfs info;
220  int retval = statfs(path.c_str(), &info);
221  if (retval != 0)
222  return result;
223 
224  switch (info.f_type) {
225  case kFsTypeAutofs:
226  result.type = kFsTypeAutofs;
227  break;
228  case kFsTypeNFS:
229  result.type = kFsTypeNFS;
230  break;
231  case kFsTypeProc:
232  result.type = kFsTypeProc;
233  break;
234  case kFsTypeBeeGFS:
235  result.type = kFsTypeBeeGFS;
236  break;
237  default:
238  result.type = kFsTypeUnknown;
239  }
240 
241 #ifdef CVMFS_HAS_STATFS_F_FLAGS
242  if (info.f_flags & ST_RDONLY)
243  result.is_rdonly = true;
244 #else
245  // On old Linux systems, fall back to access()
246  retval = access(path.c_str(), W_OK);
247  result.is_rdonly = (retval != 0);
248 #endif
249 
250 
251 
252  return result;
253 }
254 
255 
256 std::string ReadSymlink(const std::string &path) {
257  // TODO(jblomer): avoid PATH_MAX
258  char buf[PATH_MAX + 1];
259  ssize_t nchars = readlink(path.c_str(), buf, PATH_MAX);
260  if (nchars >= 0) {
261  buf[nchars] = '\0';
262  return std::string(buf);
263  }
264  return "";
265 }
266 
267 
272 std::string ResolvePath(const std::string &path) {
273  if (path.empty() || (path == "/"))
274  return "/";
275  std::string name = GetFileName(path);
276  std::string result = name;
277  if (name != path) {
278  // There is a parent path of 'path'
279  std::string parent = ResolvePath(GetParentPath(path));
280  result = parent + (parent == "/" ? "" : "/") + name;
281  }
282  char *real_result = realpath(result.c_str(), NULL);
283  if (real_result) {
284  result = real_result;
285  free(real_result);
286  }
287  if (SymlinkExists(result)) {
288  char buf[PATH_MAX + 1];
289  ssize_t nchars = readlink(result.c_str(), buf, PATH_MAX);
290  if (nchars >= 0) {
291  buf[nchars] = '\0';
292  result = buf;
293  }
294  }
295  return result;
296 }
297 
298 
299 bool IsMountPoint(const std::string &path) {
300  std::vector<std::string> mount_list = platform_mountlist();
301  std::string resolved_path = ResolvePath(path);
302  for (unsigned i = 0; i < mount_list.size(); ++i) {
303  if (mount_list[i] == resolved_path)
304  return true;
305  }
306  return false;
307 }
308 
309 
314  const std::string &path,
315  const int mode,
316  const bool ignore_failure)
317 {
318  int fd = open(path.c_str(), O_CREAT, mode);
319  if (fd >= 0) {
320  close(fd);
321  return;
322  }
323  if (ignore_failure)
324  return;
325  PANIC(NULL);
326 }
327 
328 
332 static std::string MakeShortSocketLink(const std::string &path) {
333  struct sockaddr_un sock_addr;
334  unsigned max_length = sizeof(sock_addr.sun_path);
335 
336  std::string result;
337  std::string tmp_path = CreateTempDir("/tmp/cvmfs");
338  if (tmp_path.empty())
339  return "";
340  std::string link = tmp_path + "/l";
341  result = link + "/" + GetFileName(path);
342  if (result.length() >= max_length) {
343  rmdir(tmp_path.c_str());
344  return "";
345  }
346  int retval = symlink(GetParentPath(path).c_str(), link.c_str());
347  if (retval != 0) {
348  rmdir(tmp_path.c_str());
349  return "";
350  }
351  return result;
352 }
353 
354 static void RemoveShortSocketLink(const std::string &short_path) {
355  std::string link = GetParentPath(short_path);
356  unlink(link.c_str());
357  rmdir(GetParentPath(link).c_str());
358 }
359 
360 
364 int MakeSocket(const std::string &path, const int mode) {
365  std::string short_path(path);
366  struct sockaddr_un sock_addr;
367  if (path.length() >= sizeof(sock_addr.sun_path)) {
368  // Socket paths are limited to 108 bytes (on some systems to 92 bytes),
369  // try working around
370  short_path = MakeShortSocketLink(path);
371  if (short_path.empty())
372  return -1;
373  }
374  sock_addr.sun_family = AF_UNIX;
375  strncpy(sock_addr.sun_path, short_path.c_str(),
376  sizeof(sock_addr.sun_path));
377 
378  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
379  assert(socket_fd != -1);
380 
381 #ifndef __APPLE__
382  // fchmod on a socket is not allowed under Mac OS X
383  // using default 0770 here
384  if (fchmod(socket_fd, mode) != 0)
385  goto make_socket_failure;
386 #endif
387 
388  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
389  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path)) < 0)
390  {
391  if ((errno == EADDRINUSE) && (unlink(path.c_str()) == 0)) {
392  // Second try, perhaps the file was left over
393  if (bind(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
394  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path)) < 0)
395  {
396  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
397  goto make_socket_failure;
398  }
399  } else {
400  LogCvmfs(kLogCvmfs, kLogDebug, "binding socket failed (%d)", errno);
401  goto make_socket_failure;
402  }
403  }
404 
405  if (short_path != path)
406  RemoveShortSocketLink(short_path);
407 
408  return socket_fd;
409 
410  make_socket_failure:
411  close(socket_fd);
412  if (short_path != path)
413  RemoveShortSocketLink(short_path);
414  return -1;
415 }
416 
417 
422 int MakeTcpEndpoint(const std::string &ipv4_address, int portno) {
423  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
424  assert(socket_fd != -1);
425  const int on = 1;
426  int retval = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
427  assert(retval == 0);
428 
429  struct sockaddr_in endpoint_addr;
430  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
431  endpoint_addr.sin_family = AF_INET;
432  if (ipv4_address.empty()) {
433  endpoint_addr.sin_addr.s_addr = INADDR_ANY;
434  } else {
435  retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
436  if (retval == 0) {
437  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
438  close(socket_fd);
439  return -1;
440  }
441  }
442  endpoint_addr.sin_port = htons(portno);
443 
444  retval = bind(socket_fd, reinterpret_cast<struct sockaddr *>(&endpoint_addr),
445  sizeof(endpoint_addr));
446  if (retval < 0) {
447  LogCvmfs(kLogCvmfs, kLogDebug, "binding TCP endpoint failed (%d)", errno);
448  close(socket_fd);
449  return -1;
450  }
451  return socket_fd;
452 }
453 
454 
460 int ConnectSocket(const std::string &path) {
461  std::string short_path(path);
462  struct sockaddr_un sock_addr;
463  if (path.length() >= sizeof(sock_addr.sun_path)) {
464  // Socket paths are limited to 108 bytes (on some systems to 92 bytes),
465  // try working around
466  short_path = MakeShortSocketLink(path);
467  if (short_path.empty())
468  return -1;
469  }
470  sock_addr.sun_family = AF_UNIX;
471  strncpy(sock_addr.sun_path, short_path.c_str(), sizeof(sock_addr.sun_path));
472 
473  const int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
474  assert(socket_fd != -1);
475 
476  int retval =
477  connect(socket_fd, reinterpret_cast<struct sockaddr *>(&sock_addr),
478  sizeof(sock_addr.sun_family) + sizeof(sock_addr.sun_path));
479  if (short_path != path)
480  RemoveShortSocketLink(short_path);
481 
482  if (retval < 0) {
483  close(socket_fd);
484  return -1;
485  }
486 
487  return socket_fd;
488 }
489 
490 
494 int ConnectTcpEndpoint(const std::string &ipv4_address, int portno) {
495  const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
496  assert(socket_fd != -1);
497 
498  struct sockaddr_in endpoint_addr;
499  memset(&endpoint_addr, 0, sizeof(endpoint_addr));
500  endpoint_addr.sin_family = AF_INET;
501  int retval = inet_aton(ipv4_address.c_str(), &(endpoint_addr.sin_addr));
502  if (retval == 0) {
503  LogCvmfs(kLogCvmfs, kLogDebug, "invalid IPv4 address");
504  close(socket_fd);
505  return -1;
506  }
507  endpoint_addr.sin_port = htons(portno);
508 
509  retval =
510  connect(socket_fd, reinterpret_cast<struct sockaddr *>(&endpoint_addr),
511  sizeof(endpoint_addr));
512  if (retval != 0) {
513  LogCvmfs(kLogCvmfs, kLogDebug, "failed to connect to TCP endpoint (%d)",
514  errno);
515  close(socket_fd);
516  return -1;
517  }
518  return socket_fd;
519 }
520 
521 
525 void MakePipe(int pipe_fd[2]) {
526  int retval = pipe(pipe_fd);
527  assert(retval == 0);
528 }
529 
530 
534 void WritePipe(int fd, const void *buf, size_t nbyte) {
535  ssize_t num_bytes;
536  do {
537  num_bytes = write(fd, buf, nbyte);
538  } while ((num_bytes < 0) && (errno == EINTR));
539  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
540 }
541 
542 
546 void ReadPipe(int fd, void *buf, size_t nbyte) {
547  ssize_t num_bytes;
548  do {
549  num_bytes = read(fd, buf, nbyte);
550  } while ((num_bytes < 0) && (errno == EINTR));
551  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
552 }
553 
554 
558 void ReadHalfPipe(int fd, void *buf, size_t nbyte) {
559  ssize_t num_bytes;
560  unsigned i = 0;
561  unsigned backoff_ms = 1;
562  const unsigned max_backoff_ms = 256;
563  do {
564  // When the writer is not connected, this takes ~200-300ns per call as per
565  // micro benchmarks
566  num_bytes = read(fd, buf, nbyte);
567  if ((num_bytes < 0) && (errno == EINTR))
568  continue;
569  i++;
570  // Start backing off when the busy loop reaches the ballpark of 1ms
571  if ((i > 3000) && (num_bytes == 0)) {
572  // The BackoffThrottle would pull in too many dependencies
573  SafeSleepMs(backoff_ms);
574  if (backoff_ms < max_backoff_ms) backoff_ms *= 2;
575  }
576  } while (num_bytes == 0);
577  assert((num_bytes >= 0) && (static_cast<size_t>(num_bytes) == nbyte));
578 }
579 
580 
584 void ClosePipe(int pipe_fd[2]) {
585  close(pipe_fd[0]);
586  close(pipe_fd[1]);
587 }
588 
589 
594 bool DiffTree(const std::string &path_a, const std::string &path_b) {
595  int retval;
596  std::vector<std::string> ls_a;
597  std::vector<std::string> ls_b;
598  std::vector<std::string> subdirs;
599 
600  DIR *dirp_a = opendir(path_a.c_str());
601  if (dirp_a == NULL) return false;
602  DIR *dirp_b = opendir(path_b.c_str());
603  if (dirp_b == NULL) {
604  closedir(dirp_a);
605  return false;
606  }
607 
608  platform_dirent64 *dirent;
609  while ((dirent = platform_readdir(dirp_a))) {
610  const std::string name(dirent->d_name);
611  if ((name == ".") || (name == ".."))
612  continue;
613  const std::string path = path_a + "/" + name;
614  ls_a.push_back(path);
615 
616  platform_stat64 info;
617  retval = platform_lstat(path.c_str(), &info);
618  if (retval != 0) {
619  closedir(dirp_a);
620  closedir(dirp_b);
621  return false;
622  }
623  if (S_ISDIR(info.st_mode)) subdirs.push_back(name);
624  }
625  while ((dirent = platform_readdir(dirp_b))) {
626  const std::string name(dirent->d_name);
627  if ((name == ".") || (name == ".."))
628  continue;
629  const std::string path = path_b + "/" + name;
630  ls_b.push_back(path);
631  }
632  closedir(dirp_a);
633  closedir(dirp_b);
634 
635  sort(ls_a.begin(), ls_a.end());
636  sort(ls_b.begin(), ls_b.end());
637  if (ls_a.size() != ls_b.size())
638  return false;
639  for (unsigned i = 0; i < ls_a.size(); ++i) {
640  if (GetFileName(ls_a[i]) != GetFileName(ls_b[i])) return false;
641  platform_stat64 info_a;
642  platform_stat64 info_b;
643  retval = platform_lstat(ls_a[i].c_str(), &info_a);
644  if (retval != 0) return false;
645  retval = platform_lstat(ls_b[i].c_str(), &info_b);
646  if (retval != 0) return false;
647  if ((info_a.st_mode != info_b.st_mode) ||
648  (info_a.st_uid != info_b.st_uid) ||
649  (info_a.st_gid != info_b.st_gid) ||
650  (info_a.st_size != info_b.st_size))
651  {
652  return false;
653  }
654  }
655 
656  for (unsigned i = 0; i < subdirs.size(); ++i) {
657  bool retval_subtree = DiffTree(path_a + "/" + subdirs[i],
658  path_b + "/" + subdirs[i]);
659  if (!retval_subtree) return false;
660  }
661 
662  return true;
663 }
664 
665 
669 void Nonblock2Block(int filedes) {
670  int flags = fcntl(filedes, F_GETFL);
671  assert(flags != -1);
672  int retval = fcntl(filedes, F_SETFL, flags & ~O_NONBLOCK);
673  assert(retval != -1);
674 }
675 
676 
680 void Block2Nonblock(int filedes) {
681  int flags = fcntl(filedes, F_GETFL);
682  assert(flags != -1);
683  int retval = fcntl(filedes, F_SETFL, flags | O_NONBLOCK);
684  assert(retval != -1);
685 }
686 
687 
692 void SendMsg2Socket(const int fd, const std::string &msg) {
693  (void)send(fd, &msg[0], msg.length(), MSG_NOSIGNAL);
694 }
695 
701 bool SendFd2Socket(int socket_fd, int passing_fd) {
702  union {
703  // Make sure that ctrl_msg is properly aligned.
704  struct cmsghdr align;
705  // Buffer large enough to store the file descriptor (ancillary data)
706  unsigned char buf[CMSG_SPACE(sizeof(int))];
707  } ctrl_msg;
708 
709  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
710 
711  struct msghdr msgh;
712  msgh.msg_name = NULL;
713  msgh.msg_namelen = 0;
714 
715  unsigned char dummy = 0;
716  struct iovec iov;
717  iov.iov_base = &dummy;
718  iov.iov_len = 1;
719  msgh.msg_iov = &iov;
720  msgh.msg_iovlen = 1;
721 
722  msgh.msg_control = ctrl_msg.buf;
723  msgh.msg_controllen = sizeof(ctrl_msg.buf);
724  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
725  cmsgp->cmsg_len = CMSG_LEN(sizeof(int));
726  cmsgp->cmsg_level = SOL_SOCKET;
727  cmsgp->cmsg_type = SCM_RIGHTS;
728  memcpy(CMSG_DATA(cmsgp), &passing_fd, sizeof(int));
729 
730  ssize_t retval = sendmsg(socket_fd, &msgh, 0);
731  return (retval != -1);
732 }
733 
734 
741 int RecvFdFromSocket(int msg_fd) {
742  union {
743  // Make sure that ctrl_msg is properly aligned.
744  struct cmsghdr align;
745  // Buffer large enough to store the file descriptor (ancillary data)
746  unsigned char buf[CMSG_SPACE(sizeof(int))];
747  } ctrl_msg;
748 
749  memset(ctrl_msg.buf, 0, sizeof(ctrl_msg.buf));
750 
751  struct msghdr msgh;
752  msgh.msg_name = NULL;
753  msgh.msg_namelen = 0;
754 
755  unsigned char dummy;
756  struct iovec iov;
757  iov.iov_base = &dummy;
758  iov.iov_len = 1;
759  msgh.msg_iov = &iov;
760  msgh.msg_iovlen = 1;
761 
762  msgh.msg_control = ctrl_msg.buf;
763  msgh.msg_controllen = sizeof(ctrl_msg.buf);
764 
765  ssize_t retval = recvmsg(msg_fd, &msgh, 0);
766  if (retval == -1)
767  return -errno;
768 
769  struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh);
770  assert(cmsgp != NULL);
771  if (cmsgp->cmsg_len != CMSG_LEN(sizeof(int)))
772  return -ERANGE;
773  assert(cmsgp->cmsg_level == SOL_SOCKET);
774  assert(cmsgp->cmsg_type == SCM_RIGHTS);
775 
776  int passing_fd;
777  memcpy(&passing_fd, CMSG_DATA(cmsgp), sizeof(int));
778  assert(passing_fd >= 0);
779  return passing_fd;
780 }
781 
782 
786 bool SwitchCredentials(const uid_t uid, const gid_t gid,
787  const bool temporarily)
788 {
789  LogCvmfs(kLogCvmfs, kLogDebug, "current credentials uid %d gid %d "
790  "euid %d egid %d, switching to %d %d (temp: %d)",
791  getuid(), getgid(), geteuid(), getegid(), uid, gid, temporarily);
792  int retval = 0;
793  if (temporarily) {
794  if (gid != getegid())
795  retval = setegid(gid);
796  if ((retval == 0) && (uid != geteuid()))
797  retval = seteuid(uid);
798  } else {
799  // If effective uid is not root, we must first gain root access back
800  if ((getuid() == 0) && (getuid() != geteuid())) {
801  retval = SwitchCredentials(0, getgid(), true);
802  if (!retval)
803  return false;
804  }
805  retval = setgid(gid) || setuid(uid);
806  }
807  LogCvmfs(kLogCvmfs, kLogDebug, "switch credentials result %d (%d)",
808  retval, errno);
809  return retval == 0;
810 }
811 
812 
816 bool FileExists(const std::string &path) {
817  platform_stat64 info;
818  return ((platform_lstat(path.c_str(), &info) == 0) &&
819  S_ISREG(info.st_mode));
820 }
821 
822 
826 int64_t GetFileSize(const std::string &path) {
827  platform_stat64 info;
828  int retval = platform_stat(path.c_str(), &info);
829  if (retval != 0)
830  return -1;
831  return info.st_size;
832 }
833 
834 
838 bool DirectoryExists(const std::string &path) {
839  platform_stat64 info;
840  return ((platform_lstat(path.c_str(), &info) == 0) &&
841  S_ISDIR(info.st_mode));
842 }
843 
844 
848 bool SymlinkExists(const std::string &path) {
849  platform_stat64 info;
850  return ((platform_lstat(path.c_str(), &info) == 0) &&
851  S_ISLNK(info.st_mode));
852 }
853 
854 
858 bool SymlinkForced(const std::string &src, const std::string &dest) {
859  int retval = unlink(dest.c_str());
860  if ((retval != 0) && (errno != ENOENT))
861  return false;
862  retval = symlink(src.c_str(), dest.c_str());
863  return retval == 0;
864 }
865 
866 
872  const std::string &path,
873  const mode_t mode,
874  bool verify_writable)
875 {
876  if (path == "") return false;
877 
878  int retval = mkdir(path.c_str(), mode);
879  if (retval == 0) return true;
880 
881  if ((errno == ENOENT) &&
882  (MkdirDeep(GetParentPath(path), mode, verify_writable)))
883  {
884  return MkdirDeep(path, mode, verify_writable);
885  }
886 
887  if (errno == EEXIST) {
888  platform_stat64 info;
889  if ((platform_stat(path.c_str(), &info) == 0) && S_ISDIR(info.st_mode)) {
890  if (verify_writable) {
891  retval = utimes(path.c_str(), NULL);
892  if (retval == 0)
893  return true;
894  } else {
895  return true;
896  }
897  }
898  }
899 
900  return false;
901 }
902 
903 
907 bool MakeCacheDirectories(const std::string &path, const mode_t mode) {
908  const std::string canonical_path = MakeCanonicalPath(path);
909 
910  std::string this_path = canonical_path + "/quarantaine";
911  if (!MkdirDeep(this_path, mode, false)) return false;
912 
913  this_path = canonical_path + "/ff";
914 
915  platform_stat64 stat_info;
916  if (platform_stat(this_path.c_str(), &stat_info) != 0) {
917  this_path = canonical_path + "/txn";
918  if (!MkdirDeep(this_path, mode, false))
919  return false;
920  for (int i = 0; i <= 0xff; i++) {
921  char hex[4];
922  snprintf(hex, sizeof(hex), "%02x", i);
923  this_path = canonical_path + "/" + std::string(hex);
924  if (!MkdirDeep(this_path, mode, false))
925  return false;
926  }
927  }
928  return true;
929 }
930 
931 
938 int TryLockFile(const std::string &path) {
939  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
940  if (fd_lockfile < 0)
941  return -1;
942 
943  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
944  close(fd_lockfile);
945  if (errno != EWOULDBLOCK)
946  return -1;
947  return -2;
948  }
949 
950  return fd_lockfile;
951 }
952 
953 
960 int WritePidFile(const std::string &path) {
961  const int fd = open(path.c_str(), O_CREAT | O_RDWR, 0600);
962  if (fd < 0)
963  return -1;
964  if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
965  close(fd);
966  if (errno != EWOULDBLOCK)
967  return -1;
968  return -2;
969  }
970 
971  // Don't leak the file descriptor to exec'd children
972  int flags = fcntl(fd, F_GETFD);
973  assert(flags != -1);
974  flags |= FD_CLOEXEC;
975  flags = fcntl(fd, F_SETFD, flags);
976  assert(flags != -1);
977 
978  char buf[64];
979 
980  snprintf(buf, sizeof(buf), "%" PRId64 "\n", static_cast<uint64_t>(getpid()));
981  bool retval =
982  (ftruncate(fd, 0) == 0) && SafeWrite(fd, buf, strlen(buf));
983  if (!retval) {
984  UnlockFile(fd);
985  return -1;
986  }
987  return fd;
988 }
989 
990 
996 int LockFile(const std::string &path) {
997  const int fd_lockfile = open(path.c_str(), O_RDONLY | O_CREAT, 0600);
998  if (fd_lockfile < 0)
999  return -1;
1000 
1001 
1002  if (flock(fd_lockfile, LOCK_EX | LOCK_NB) != 0) {
1003  if (errno != EWOULDBLOCK) {
1004  close(fd_lockfile);
1005  return -1;
1006  }
1007  LogCvmfs(kLogCvmfs, kLogSyslog, "another process holds %s, waiting.",
1008  path.c_str());
1009  if (flock(fd_lockfile, LOCK_EX) != 0) {
1010  close(fd_lockfile);
1011  return -1;
1012  }
1013  LogCvmfs(kLogCvmfs, kLogSyslog, "lock %s acquired", path.c_str());
1014  }
1015 
1016  return fd_lockfile;
1017 }
1018 
1019 
1020 void UnlockFile(const int filedes) {
1021  int retval = flock(filedes, LOCK_UN);
1022  assert(retval == 0);
1023  close(filedes);
1024 }
1025 
1026 
1030 FILE *CreateTempFile(const std::string &path_prefix, const int mode,
1031  const char *open_flags, std::string *final_path)
1032 {
1033  *final_path = path_prefix + ".XXXXXX";
1034  char *tmp_file = strdupa(final_path->c_str());
1035  int tmp_fd = mkstemp(tmp_file);
1036  if (tmp_fd < 0) {
1037  return NULL;
1038  }
1039  if (fchmod(tmp_fd, mode) != 0) {
1040  close(tmp_fd);
1041  return NULL;
1042  }
1043 
1044  *final_path = tmp_file;
1045  FILE *tmp_fp = fdopen(tmp_fd, open_flags);
1046  if (!tmp_fp) {
1047  close(tmp_fd);
1048  unlink(tmp_file);
1049  return NULL;
1050  }
1051 
1052  return tmp_fp;
1053 }
1054 
1055 
1059 std::string CreateTempPath(const std::string &path_prefix, const int mode) {
1060  std::string result;
1061  FILE *f = CreateTempFile(path_prefix, mode, "w", &result);
1062  if (!f)
1063  return "";
1064  fclose(f);
1065  return result;
1066 }
1067 
1068 
1072 std::string CreateTempDir(const std::string &path_prefix) {
1073  std::string dir = path_prefix + ".XXXXXX";
1074  char *tmp_dir = strdupa(dir.c_str());
1075  tmp_dir = mkdtemp(tmp_dir);
1076  if (tmp_dir == NULL)
1077  return "";
1078  return std::string(tmp_dir);
1079 }
1080 
1081 
1086  char cwd[PATH_MAX];
1087  return (getcwd(cwd, sizeof(cwd)) != NULL) ? std::string(cwd) : std::string();
1088 }
1089 
1090 
1095  public:
1096  bool success;
1098  success = true;
1099  }
1100  void RemoveFile(const std::string &parent_path, const std::string &name) {
1101  int retval = unlink((parent_path + "/" + name).c_str());
1102  if (retval != 0)
1103  success = false;
1104  }
1105  void RemoveDir(const std::string &parent_path, const std::string &name) {
1106  int retval = rmdir((parent_path + "/" + name).c_str());
1107  if (retval != 0)
1108  success = false;
1109  }
1110  bool TryRemoveDir(const std::string &parent_path, const std::string &name) {
1111  int retval = rmdir((parent_path + "/" + name).c_str());
1112  return (retval != 0);
1113  }
1114 };
1115 
1116 
1120 bool RemoveTree(const std::string &path) {
1121  platform_stat64 info;
1122  int retval = platform_lstat(path.c_str(), &info);
1123  if (retval != 0)
1124  return errno == ENOENT;
1125  if (!S_ISDIR(info.st_mode))
1126  return false;
1127 
1128  RemoveTreeHelper *remove_tree_helper = new RemoveTreeHelper();
1129  FileSystemTraversal<RemoveTreeHelper> traversal(remove_tree_helper, "",
1130  true);
1138  traversal.Recurse(path);
1139  bool result = remove_tree_helper->success;
1140  delete remove_tree_helper;
1141 
1142  return result;
1143 }
1144 
1145 
1149 std::vector<std::string> FindFilesBySuffix(
1150  const std::string &dir,
1151  const std::string &suffix)
1152 {
1153  std::vector<std::string> result;
1154  DIR *dirp = opendir(dir.c_str());
1155  if (!dirp)
1156  return result;
1157 
1158  platform_dirent64 *dirent;
1159  while ((dirent = platform_readdir(dirp))) {
1160  const std::string name(dirent->d_name);
1161  if ((name.length() >= suffix.length()) &&
1162  (name.substr(name.length()-suffix.length()) == suffix))
1163  {
1164  result.push_back(dir + "/" + name);
1165  }
1166  }
1167  closedir(dirp);
1168  std::sort(result.begin(), result.end());
1169  return result;
1170 }
1171 
1172 
1176 std::vector<std::string> FindFilesByPrefix(
1177  const std::string &dir,
1178  const std::string &prefix)
1179 {
1180  std::vector<std::string> result;
1181  DIR *dirp = opendir(dir.c_str());
1182  if (!dirp)
1183  return result;
1184 
1185  platform_dirent64 *dirent;
1186  while ((dirent = platform_readdir(dirp))) {
1187  const std::string name(dirent->d_name);
1188  if ((name.length() >= prefix.length()) &&
1189  (name.substr(0, prefix.length()) == prefix))
1190  {
1191  result.push_back(dir + "/" + name);
1192  }
1193  }
1194  closedir(dirp);
1195  std::sort(result.begin(), result.end());
1196  return result;
1197 }
1198 
1199 
1204 std::vector<std::string> FindDirectories(const std::string &parent_dir) {
1205  std::vector<std::string> result;
1206  DIR *dirp = opendir(parent_dir.c_str());
1207  if (!dirp)
1208  return result;
1209 
1210  platform_dirent64 *dirent;
1211  while ((dirent = platform_readdir(dirp))) {
1212  const std::string name(dirent->d_name);
1213  if ((name == ".") || (name == ".."))
1214  continue;
1215  const std::string path = parent_dir + "/" + name;
1216 
1217  platform_stat64 info;
1218  int retval = platform_stat(path.c_str(), &info);
1219  if (retval != 0)
1220  continue;
1221  if (S_ISDIR(info.st_mode))
1222  result.push_back(path);
1223  }
1224  closedir(dirp);
1225  sort(result.begin(), result.end());
1226  return result;
1227 }
1228 
1229 
1233 bool ListDirectory(const std::string &directory,
1234  std::vector<std::string> *names,
1235  std::vector<mode_t> *modes)
1236 {
1237  DIR *dirp = opendir(directory.c_str());
1238  if (!dirp)
1239  return false;
1240 
1241  platform_dirent64 *dirent;
1242  while ((dirent = platform_readdir(dirp))) {
1243  const std::string name(dirent->d_name);
1244  if ((name == ".") || (name == ".."))
1245  continue;
1246  const std::string path = directory + "/" + name;
1247 
1248  platform_stat64 info;
1249  int retval = platform_lstat(path.c_str(), &info);
1250  if (retval != 0) {
1251  closedir(dirp);
1252  return false;
1253  }
1254 
1255  names->push_back(name);
1256  modes->push_back(info.st_mode);
1257  }
1258  closedir(dirp);
1259 
1260  SortTeam(names, modes);
1261  return true;
1262 }
1263 
1264 
1269 std::string FindExecutable(const std::string &exe) {
1270  if (exe.empty())
1271  return "";
1272 
1273  std::vector<std::string> search_paths;
1274  if (exe[0] == '/') {
1275  search_paths.push_back(GetParentPath(exe));
1276  } else {
1277  char *path_env = getenv("PATH");
1278  if (path_env) {
1279  search_paths = SplitString(path_env, ':');
1280  }
1281  }
1282 
1283  for (unsigned i = 0; i < search_paths.size(); ++i) {
1284  if (search_paths[i].empty())
1285  continue;
1286  if (search_paths[i][0] != '/')
1287  continue;
1288 
1289  std::string path = search_paths[i] + "/" + GetFileName(exe);
1290  platform_stat64 info;
1291  int retval = platform_stat(path.c_str(), &info);
1292  if (retval != 0)
1293  continue;
1294  if (!S_ISREG(info.st_mode))
1295  continue;
1296  retval = access(path.c_str(), X_OK);
1297  if (retval != 0)
1298  continue;
1299 
1300  return path;
1301  }
1302 
1303  return "";
1304 }
1305 
1306 
1307 std::string GetUserName() {
1308  struct passwd pwd;
1309  struct passwd *result = NULL;
1310  int bufsize = 16 * 1024;
1311  char *buf = static_cast<char *>(smalloc(bufsize));
1312  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1313  bufsize *= 2;
1314  buf = static_cast<char *>(srealloc(buf, bufsize));
1315  }
1316  if (result == NULL) {
1317  free(buf);
1318  return "";
1319  }
1320  std::string user_name = pwd.pw_name;
1321  free(buf);
1322  return user_name;
1323 }
1324 
1325 std::string GetShell() {
1326  struct passwd pwd;
1327  struct passwd *result = NULL;
1328  int bufsize = 16 * 1024;
1329  char *buf = static_cast<char *>(smalloc(bufsize));
1330  while (getpwuid_r(geteuid(), &pwd, buf, bufsize, &result) == ERANGE) {
1331  bufsize *= 2;
1332  buf = static_cast<char *>(srealloc(buf, bufsize));
1333  }
1334  if (result == NULL) {
1335  free(buf);
1336  return "";
1337  }
1338  std::string shell = pwd.pw_shell;
1339  free(buf);
1340  return shell;
1341 }
1342 
1346 bool GetUserNameOf(uid_t uid, std::string *username) {
1347  struct passwd pwd;
1348  struct passwd *result = NULL;
1349  int bufsize = 16 * 1024;
1350  char *buf = static_cast<char *>(smalloc(bufsize));
1351  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1352  bufsize *= 2;
1353  buf = static_cast<char *>(srealloc(buf, bufsize));
1354  }
1355  if (result == NULL) {
1356  free(buf);
1357  return false;
1358  }
1359  if (username)
1360  *username = result->pw_name;
1361  free(buf);
1362  return true;
1363 }
1364 
1365 
1369 bool GetUidOf(const std::string &username, uid_t *uid, gid_t *main_gid) {
1370  struct passwd pwd;
1371  struct passwd *result = NULL;
1372  int bufsize = 16 * 1024;
1373  char *buf = static_cast<char *>(smalloc(bufsize));
1374  while (getpwnam_r(username.c_str(), &pwd, buf, bufsize, &result) == ERANGE) {
1375  bufsize *= 2;
1376  buf = static_cast<char *>(srealloc(buf, bufsize));
1377  }
1378  if (result == NULL) {
1379  free(buf);
1380  return false;
1381  }
1382  *uid = result->pw_uid;
1383  *main_gid = result->pw_gid;
1384  free(buf);
1385  return true;
1386 }
1387 
1388 
1392 bool GetGidOf(const std::string &groupname, gid_t *gid) {
1393  struct group grp;
1394  struct group *result = NULL;
1395  int bufsize = 16 * 1024;
1396  char *buf = static_cast<char *>(smalloc(bufsize));
1397  while (getgrnam_r(groupname.c_str(), &grp, buf, bufsize, &result) == ERANGE) {
1398  bufsize *= 2;
1399  buf = static_cast<char *>(srealloc(buf, bufsize));
1400  }
1401  if (result == NULL) {
1402  free(buf);
1403  return false;
1404  }
1405  *gid = result->gr_gid;
1406  free(buf);
1407  return true;
1408 }
1409 
1415 mode_t GetUmask() {
1417  const mode_t my_umask = umask(0);
1418  umask(my_umask);
1419  return my_umask;
1420 }
1421 
1422 
1426 bool AddGroup2Persona(const gid_t gid) {
1427  int ngroups = getgroups(0, NULL);
1428  if (ngroups < 0)
1429  return false;
1430  gid_t *groups = static_cast<gid_t *>(smalloc((ngroups+1) * sizeof(gid_t)));
1431  int retval = getgroups(ngroups, groups);
1432  if (retval < 0) {
1433  free(groups);
1434  return false;
1435  }
1436  for (int i = 0; i < ngroups; ++i) {
1437  if (groups[i] == gid) {
1438  free(groups);
1439  return true;
1440  }
1441  }
1442  groups[ngroups] = gid;
1443  retval = setgroups(ngroups+1, groups);
1444  free(groups);
1445  return retval == 0;
1446 }
1447 
1448 
1449 std::string GetHomeDirectory() {
1450  uid_t uid = getuid();
1451  struct passwd pwd;
1452  struct passwd *result = NULL;
1453  int bufsize = 16 * 1024;
1454  char *buf = static_cast<char *>(smalloc(bufsize));
1455  while (getpwuid_r(uid, &pwd, buf, bufsize, &result) == ERANGE) {
1456  bufsize *= 2;
1457  buf = static_cast<char *>(srealloc(buf, bufsize));
1458  }
1459  if (result == NULL) {
1460  free(buf);
1461  return "";
1462  }
1463  std::string home_dir = result->pw_dir;
1464  free(buf);
1465  return home_dir;
1466 }
1467 
1468 
1473 int SetLimitNoFile(unsigned limit_nofile) {
1474  struct rlimit rpl;
1475  memset(&rpl, 0, sizeof(rpl));
1476  getrlimit(RLIMIT_NOFILE, &rpl);
1477  if (rpl.rlim_max < limit_nofile)
1478  rpl.rlim_max = limit_nofile;
1479  rpl.rlim_cur = limit_nofile;
1480  int retval = setrlimit(RLIMIT_NOFILE, &rpl);
1481  if (retval == 0)
1482  return 0;
1483 
1484 #ifdef HAS_VALGRIND_HEADERS
1485  return RUNNING_ON_VALGRIND ? -2 : -1;
1486 #else
1487  return -1;
1488 #endif
1489 }
1490 
1491 
1495 void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit) {
1496  *soft_limit = 0;
1497  *hard_limit = 0;
1498 
1499  struct rlimit rpl;
1500  memset(&rpl, 0, sizeof(rpl));
1501  getrlimit(RLIMIT_NOFILE, &rpl);
1502  *soft_limit = rpl.rlim_cur;
1503 
1504 #ifdef __APPLE__
1505  int value = sysconf(_SC_OPEN_MAX);
1506  assert(value > 0);
1507  *hard_limit = value;
1508 #else
1509  *hard_limit = rpl.rlim_max;
1510 #endif
1511 }
1512 
1513 
1514 std::vector<LsofEntry> Lsof(const std::string &path) {
1515  std::vector<LsofEntry> result;
1516 
1517  std::vector<std::string> proc_names;
1518  std::vector<mode_t> proc_modes;
1519  ListDirectory("/proc", &proc_names, &proc_modes);
1520 
1521  for (unsigned i = 0; i < proc_names.size(); ++i) {
1522  if (!S_ISDIR(proc_modes[i]))
1523  continue;
1524  if (proc_names[i].find_first_not_of("1234567890") != std::string::npos)
1525  continue;
1526 
1527  std::vector<std::string> fd_names;
1528  std::vector<mode_t> fd_modes;
1529  std::string proc_dir = "/proc/" + proc_names[i];
1530  std::string fd_dir = proc_dir + "/fd";
1531  bool rvb = ListDirectory(fd_dir, &fd_names, &fd_modes);
1532  uid_t proc_uid = 0;
1533 
1534  // The working directory of the process requires special handling
1535  if (rvb) {
1536  platform_stat64 info;
1537  platform_stat(proc_dir.c_str(), &info);
1538  proc_uid = info.st_uid;
1539 
1540  std::string cwd = ReadSymlink(proc_dir + "/cwd");
1541  if (HasPrefix(cwd + "/", path + "/", false /* ignore_case */)) {
1542  LsofEntry entry;
1543  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1544  entry.owner = proc_uid;
1545  entry.read_only = true; // A bit sloppy but good enough for the moment
1546  entry.executable = ReadSymlink(proc_dir + "/exe");
1547  entry.path = cwd;
1548  result.push_back(entry);
1549  }
1550  }
1551 
1552  for (unsigned j = 0; j < fd_names.size(); ++j) {
1553  if (!S_ISLNK(fd_modes[j]))
1554  continue;
1555  if (fd_names[j].find_first_not_of("1234567890") != std::string::npos)
1556  continue;
1557 
1558  std::string target = ReadSymlink(fd_dir + "/" + fd_names[j]);
1559  if (!HasPrefix(target + "/", path + "/", false /* ignore_case */))
1560  continue;
1561 
1562  LsofEntry entry;
1563  entry.pid = static_cast<pid_t>(String2Uint64(proc_names[i]));
1564  entry.owner = proc_uid;
1565  entry.read_only = !((fd_modes[j] & S_IWUSR) == S_IWUSR);
1566  entry.executable = ReadSymlink(proc_dir + "/exe");
1567  entry.path = target;
1568  result.push_back(entry);
1569  }
1570  }
1571 
1572  return result;
1573 }
1574 
1575 
1576 bool ProcessExists(pid_t pid) {
1577  assert(pid > 0);
1578  int retval = kill(pid, 0);
1579  if (retval == 0)
1580  return true;
1581  return (errno != ESRCH);
1582 }
1583 
1584 
1588 void BlockSignal(int signum) {
1589  sigset_t sigset;
1590  int retval = sigemptyset(&sigset);
1591  assert(retval == 0);
1592  retval = sigaddset(&sigset, signum);
1593  assert(retval == 0);
1594  retval = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1595  assert(retval == 0);
1596 }
1597 
1598 
1603 void WaitForSignal(int signum) {
1604  int retval;
1605  do {
1606  retval = platform_sigwait(signum);
1607  } while ((retval != signum) && (errno == EINTR));
1608  assert(retval == signum);
1609 }
1610 
1611 
1615 int WaitForChild(pid_t pid) {
1616  assert(pid > 0);
1617  int statloc;
1618  while (true) {
1619  pid_t retval = waitpid(pid, &statloc, 0);
1620  if (retval == -1) {
1621  if (errno == EINTR)
1622  continue;
1623  PANIC(NULL);
1624  }
1625  assert(retval == pid);
1626  break;
1627  }
1628  if (WIFEXITED(statloc))
1629  return WEXITSTATUS(statloc);
1630  return -1;
1631 }
1632 
1633 
1637 void Daemonize() {
1638  pid_t pid;
1639  int statloc;
1640  if ((pid = fork()) == 0) {
1641  int retval = setsid();
1642  assert(retval != -1);
1643  if ((pid = fork()) == 0) {
1644  int null_read = open("/dev/null", O_RDONLY);
1645  int null_write = open("/dev/null", O_WRONLY);
1646  assert((null_read >= 0) && (null_write >= 0));
1647  retval = dup2(null_read, 0);
1648  assert(retval == 0);
1649  retval = dup2(null_write, 1);
1650  assert(retval == 1);
1651  retval = dup2(null_write, 2);
1652  assert(retval == 2);
1653  close(null_read);
1654  close(null_write);
1655  LogCvmfs(kLogCvmfs, kLogDebug, "daemonized");
1656  } else {
1657  assert(pid > 0);
1658  _exit(0);
1659  }
1660  } else {
1661  assert(pid > 0);
1662  waitpid(pid, &statloc, 0);
1663  _exit(0);
1664  }
1665 }
1666 
1667 
1669  int *fd_stdin,
1670  int *fd_stdout,
1671  int *fd_stderr,
1672  const std::string &binary_path,
1673  const std::vector<std::string> &argv,
1674  const bool double_fork,
1675  pid_t *child_pid
1676 ) {
1677  int pipe_stdin[2];
1678  int pipe_stdout[2];
1679  int pipe_stderr[2];
1680  MakePipe(pipe_stdin);
1681  MakePipe(pipe_stdout);
1682  MakePipe(pipe_stderr);
1683 
1684  std::set<int> preserve_fildes;
1685  preserve_fildes.insert(0);
1686  preserve_fildes.insert(1);
1687  preserve_fildes.insert(2);
1688  std::map<int, int> map_fildes;
1689  map_fildes[pipe_stdin[0]] = 0; // Reading end of pipe_stdin
1690  map_fildes[pipe_stdout[1]] = 1; // Writing end of pipe_stdout
1691  map_fildes[pipe_stderr[1]] = 2; // Writing end of pipe_stderr
1692  std::vector<std::string> cmd_line;
1693  cmd_line.push_back(binary_path);
1694  cmd_line.insert(cmd_line.end(), argv.begin(), argv.end());
1695 
1696  if (!ManagedExec(cmd_line,
1697  preserve_fildes,
1698  map_fildes,
1699  true /* drop_credentials */,
1700  false /* clear_env */,
1701  double_fork,
1702  child_pid))
1703  {
1704  ClosePipe(pipe_stdin);
1705  ClosePipe(pipe_stdout);
1706  ClosePipe(pipe_stderr);
1707  return false;
1708  }
1709 
1710  close(pipe_stdin[0]);
1711  close(pipe_stdout[1]);
1712  close(pipe_stderr[1]);
1713  *fd_stdin = pipe_stdin[1];
1714  *fd_stdout = pipe_stdout[0];
1715  *fd_stderr = pipe_stderr[0];
1716  return true;
1717 }
1718 
1719 
1724 bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr) {
1725  const bool double_fork = true;
1726  return ExecuteBinary(fd_stdin, fd_stdout, fd_stderr, "/bin/sh",
1727  std::vector<std::string>(), double_fork);
1728 }
1729 
1730 struct ForkFailures { // TODO(rmeusel): C++11 (type safe enum)
1731  enum Names {
1740  };
1741 
1742  static std::string ToString(const Names name) {
1743  switch (name) {
1744  case kSendPid:
1745  return "Sending PID";
1746 
1747  default:
1748  case kUnknown:
1749  return "Unknown Status";
1750  case kFailDupFd:
1751  return "Duplicate File Descriptor";
1752  case kFailGetMaxFd:
1753  return "Read maximal File Descriptor";
1754  case kFailGetFdFlags:
1755  return "Read File Descriptor Flags";
1756  case kFailSetFdFlags:
1757  return "Set File Descriptor Flags";
1758  case kFailDropCredentials:
1759  return "Lower User Permissions";
1760  case kFailExec:
1761  return "Invoking execvp()";
1762  }
1763  }
1764 };
1765 
1779 bool ManagedExec(const std::vector<std::string> &command_line,
1780  const std::set<int> &preserve_fildes,
1781  const std::map<int, int> &map_fildes,
1782  const bool drop_credentials,
1783  const bool clear_env,
1784  const bool double_fork,
1785  pid_t *child_pid)
1786 {
1787  assert(command_line.size() >= 1);
1788 
1789  Pipe pipe_fork;
1790  pid_t pid = fork();
1791  assert(pid >= 0);
1792  if (pid == 0) {
1793  pid_t pid_grand_child;
1794  int max_fd;
1795  int fd_flags;
1797 
1798  if (clear_env) {
1799 #ifdef __APPLE__
1800  environ = NULL;
1801 #else
1802  int retval = clearenv();
1803  assert(retval == 0);
1804 #endif
1805  }
1806 
1807  const char *argv[command_line.size() + 1];
1808  for (unsigned i = 0; i < command_line.size(); ++i)
1809  argv[i] = command_line[i].c_str();
1810  argv[command_line.size()] = NULL;
1811 
1812  // Child, map file descriptors
1813  for (std::map<int, int>::const_iterator i = map_fildes.begin(),
1814  iEnd = map_fildes.end(); i != iEnd; ++i)
1815  {
1816  int retval = dup2(i->first, i->second);
1817  if (retval == -1) {
1818  failed = ForkFailures::kFailDupFd;
1819  goto fork_failure;
1820  }
1821  }
1822 
1823  // Child, close file descriptors
1824  max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
1825  if (max_fd < 0) {
1826  failed = ForkFailures::kFailGetMaxFd;
1827  goto fork_failure;
1828  }
1829  for (int fd = 0; fd < max_fd; fd++) {
1830  if ((fd != pipe_fork.write_end) && (preserve_fildes.count(fd) == 0)) {
1831  close(fd);
1832  }
1833  }
1834 
1835  // Double fork to disconnect from parent
1836  if (double_fork) {
1837  pid_grand_child = fork();
1838  assert(pid_grand_child >= 0);
1839  if (pid_grand_child != 0) _exit(0);
1840  }
1841 
1842  fd_flags = fcntl(pipe_fork.write_end, F_GETFD);
1843  if (fd_flags < 0) {
1845  goto fork_failure;
1846  }
1847  fd_flags |= FD_CLOEXEC;
1848  if (fcntl(pipe_fork.write_end, F_SETFD, fd_flags) < 0) {
1850  goto fork_failure;
1851  }
1852 
1853 #ifdef DEBUGMSG
1854  assert(setenv("__CVMFS_DEBUG_MODE__", "yes", 1) == 0);
1855 #endif
1856  if (drop_credentials && !SwitchCredentials(geteuid(), getegid(), false)) {
1858  goto fork_failure;
1859  }
1860 
1861  // retrieve the PID of the new (grand) child process and send it to the
1862  // grand father
1863  pid_grand_child = getpid();
1864  failed = ForkFailures::kSendPid;
1865  pipe_fork.Write(&failed, sizeof(failed));
1866  pipe_fork.Write(pid_grand_child);
1867 
1868  execvp(command_line[0].c_str(), const_cast<char **>(argv));
1869 
1870  failed = ForkFailures::kFailExec;
1871 
1872  fork_failure:
1873  pipe_fork.Write(&failed, sizeof(failed));
1874  _exit(1);
1875  }
1876  if (double_fork) {
1877  int statloc;
1878  waitpid(pid, &statloc, 0);
1879  }
1880 
1881  close(pipe_fork.write_end);
1882 
1883  // Either the PID or a return value is sent
1884  ForkFailures::Names status_code;
1885  bool retcode = pipe_fork.Read(&status_code, sizeof(status_code));
1886  assert(retcode);
1887  if (status_code != ForkFailures::kSendPid) {
1888  close(pipe_fork.read_end);
1889  LogCvmfs(kLogCvmfs, kLogDebug, "managed execve failed (%s)",
1890  ForkFailures::ToString(status_code).c_str());
1891  return false;
1892  }
1893 
1894  // read the PID of the spawned process if requested
1895  // (the actual read needs to be done in any case!)
1896  pid_t buf_child_pid = 0;
1897  retcode = pipe_fork.Read(&buf_child_pid);
1898  assert(retcode);
1899  if (child_pid != NULL)
1900  *child_pid = buf_child_pid;
1901  close(pipe_fork.read_end);
1902  LogCvmfs(kLogCvmfs, kLogDebug, "execve'd %s (PID: %d)",
1903  command_line[0].c_str(),
1904  static_cast<int>(buf_child_pid));
1905  return true;
1906 }
1907 
1908 
1913 void SafeSleepMs(const unsigned ms) {
1914  struct timeval wait_for;
1915  wait_for.tv_sec = ms / 1000;
1916  wait_for.tv_usec = (ms % 1000) * 1000;
1917  select(0, NULL, NULL, NULL, &wait_for);
1918 }
1919 
1920 
1924 bool SafeWrite(int fd, const void *buf, size_t nbyte) {
1925  while (nbyte) {
1926  ssize_t retval = write(fd, buf, nbyte);
1927  if (retval < 0) {
1928  if (errno == EINTR)
1929  continue;
1930  return false;
1931  }
1932  assert(static_cast<size_t>(retval) <= nbyte);
1933  buf = reinterpret_cast<const char *>(buf) + retval;
1934  nbyte -= retval;
1935  }
1936  return true;
1937 }
1938 
1942 bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt) {
1943  unsigned nbytes = 0;
1944  for (unsigned i = 0; i < iovcnt; ++i)
1945  nbytes += iov[i].iov_len;
1946  unsigned iov_idx = 0;
1947 
1948  while (nbytes) {
1949  ssize_t retval =
1950  writev(fd, &iov[iov_idx], static_cast<int>(iovcnt - iov_idx));
1951  if (retval < 0) {
1952  if (errno == EINTR)
1953  continue;
1954  return false;
1955  }
1956  assert(static_cast<size_t>(retval) <= nbytes);
1957  nbytes -= retval;
1958 
1959  unsigned sum_written_blocks = 0;
1960  while ((sum_written_blocks + iov[iov_idx].iov_len) <=
1961  static_cast<size_t>(retval))
1962  {
1963  sum_written_blocks += iov[iov_idx].iov_len;
1964  iov_idx++;
1965  if (iov_idx == iovcnt) {
1966  assert(sum_written_blocks == static_cast<size_t>(retval));
1967  return true;
1968  }
1969  }
1970  unsigned offset = retval - sum_written_blocks;
1971  iov[iov_idx].iov_len -= offset;
1972  iov[iov_idx].iov_base =
1973  reinterpret_cast<char *>(iov[iov_idx].iov_base) + offset;
1974  }
1975 
1976  return true;
1977 }
1978 
1979 
1983 ssize_t SafeRead(int fd, void *buf, size_t nbyte) {
1984  ssize_t total_bytes = 0;
1985  while (nbyte) {
1986  ssize_t retval = read(fd, buf, nbyte);
1987  if (retval < 0) {
1988  if (errno == EINTR)
1989  continue;
1990  return -1;
1991  } else if (retval == 0) {
1992  return total_bytes;
1993  }
1994  assert(static_cast<size_t>(retval) <= nbyte);
1995  buf = reinterpret_cast<char *>(buf) + retval;
1996  nbyte -= retval;
1997  total_bytes += retval;
1998  }
1999  return total_bytes;
2000 }
2001 
2002 
2006 bool SafeReadToString(int fd, std::string *final_result) {
2007  if (!final_result) {return false;}
2008 
2009  std::string tmp_result;
2010  static const int buf_size = 4096;
2011  char buf[4096];
2012  ssize_t total_bytes = -1;
2013  do {
2014  total_bytes = SafeRead(fd, buf, buf_size);
2015  if (total_bytes < 0) {return false;}
2016  tmp_result.append(buf, total_bytes);
2017  } while (total_bytes == buf_size);
2018  final_result->swap(tmp_result);
2019  return true;
2020 }
2021 
2022 bool SafeWriteToFile(const std::string &content,
2023  const std::string &path,
2024  int mode) {
2025  int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
2026  if (fd < 0) return false;
2027  bool retval = SafeWrite(fd, content.data(), content.size());
2028  close(fd);
2029  return retval;
2030 }
2031 
2032 
2033 #ifdef CVMFS_NAMESPACE_GUARD
2034 } // namespace CVMFS_NAMESPACE_GUARD
2035 #endif
bool MakeCacheDirectories(const std::string &path, const mode_t mode)
Definition: posix.cc:907
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
mode_t GetUmask()
Definition: posix.cc:1415
uid_t owner
Definition: posix.h:57
void RemoveFile(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1100
int MakeSocket(const std::string &path, const int mode)
Definition: posix.cc:364
struct stat64 platform_stat64
bool SymlinkForced(const std::string &src, const std::string &dest)
Definition: posix.cc:858
std::string GetFileName(const std::string &path)
Definition: posix.cc:162
int MakeTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:422
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:288
std::string GetUserName()
Definition: posix.cc:1307
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:313
#define PANIC(...)
Definition: exception.h:26
bool GetUserNameOf(uid_t uid, std::string *username)
Definition: posix.cc:1346
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1030
int ConnectTcpEndpoint(const std::string &ipv4_address, int portno)
Definition: posix.cc:494
EFileSystemTypes type
Definition: posix.h:51
void RemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1105
bool Shell(int *fd_stdin, int *fd_stdout, int *fd_stderr)
Definition: posix.cc:1724
bool IsHttpUrl(const std::string &path)
Definition: posix.cc:204
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:1779
static void RemoveShortSocketLink(const std::string &short_path)
Definition: posix.cc:354
void Daemonize()
Definition: posix.cc:1637
static pthread_mutex_t getumask_mutex
Definition: posix.cc:90
std::string CreateTempPath(const std::string &path_prefix, const int mode)
Definition: posix.cc:1059
#define ST_RDONLY
Definition: posix.cc:66
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:1924
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:692
assert((mem||(size==0))&&"Out Of Memory")
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2022
std::string FindExecutable(const std::string &exe)
Definition: posix.cc:1269
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:701
VoidCallback fn_leave_dir
Definition: fs_traversal.h:46
bool TryRemoveDir(const std::string &parent_path, const std::string &name)
Definition: posix.cc:1110
std::string GetParentPath(const std::string &path)
Definition: posix.cc:131
int platform_stat(const char *path, platform_stat64 *buf)
bool AddGroup2Persona(const gid_t gid)
Definition: posix.cc:1426
void MakePipe(int pipe_fd[2])
Definition: posix.cc:525
std::vector< std::string > FindDirectories(const std::string &parent_dir)
Definition: posix.cc:1204
bool is_rdonly
Definition: posix.h:52
int SetLimitNoFile(unsigned limit_nofile)
Definition: posix.cc:1473
std::string path
Definition: posix.h:60
bool SymlinkExists(const std::string &path)
Definition: posix.cc:848
bool FileExists(const std::string &path)
Definition: posix.cc:816
std::string GetAbsolutePath(const std::string &path)
Definition: posix.cc:196
void SplitPath(const std::string &path, std::string *dirname, std::string *filename)
Definition: posix.cc:112
void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit)
Definition: posix.cc:1495
std::string executable
Definition: posix.h:59
#define strdupa(s)
Definition: platform_osx.h:285
VoidCallback fn_new_file
Definition: fs_traversal.h:47
void ReadHalfPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:558
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:1983
FileSystemInfo GetFileSystemInfo(const std::string &path)
Definition: posix.cc:216
void Nonblock2Block(int filedes)
Definition: posix.cc:669
int platform_sigwait(const int signum)
static std::string MakeShortSocketLink(const std::string &path)
Definition: posix.cc:332
int WaitForChild(pid_t pid)
Definition: posix.cc:1615
std::vector< std::string > platform_mountlist()
bool read_only
Definition: posix.h:58
int platform_lstat(const char *path, platform_stat64 *buf)
int TryLockFile(const std::string &path)
Definition: posix.cc:938
bool MkdirDeep(const std::string &path, const mode_t mode, bool verify_writable)
Definition: posix.cc:871
int LockFile(const std::string &path)
Definition: posix.cc:996
string ResolvePath(const std::string &path)
std::string GetHomeDirectory()
Definition: posix.cc:1449
void WaitForSignal(int signum)
Definition: posix.cc:1603
std::string GetShell()
Definition: posix.cc:1325
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:70
pid_t pid
Definition: posix.h:56
bool GetGidOf(const std::string &groupname, gid_t *gid)
Definition: posix.cc:1392
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1072
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:265
bool DirectoryExists(const std::string &path)
Definition: posix.cc:838
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:1668
bool RemoveTree(const std::string &path)
Definition: posix.cc:1120
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2006
int WritePidFile(const std::string &path)
Definition: posix.cc:960
int ConnectSocket(const std::string &path)
Definition: posix.cc:460
uint64_t String2Uint64(const string &value)
Definition: string.cc:228
Definition: posix.h:183
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:1369
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:190
std::vector< std::string > FindFilesByPrefix(const std::string &dir, const std::string &prefix)
Definition: posix.cc:1176
bool SwitchCredentials(const uid_t uid, const gid_t gid, const bool temporarily)
Definition: posix.cc:786
std::string ReadSymlink(const std::string &path)
Definition: posix.cc:256
std::vector< LsofEntry > Lsof(const std::string &path)
Definition: posix.cc:1514
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:1233
platform_dirent64 * platform_readdir(DIR *dirp)
Definition: posix.h:55
int64_t GetFileSize(const std::string &path)
Definition: posix.cc:826
#define MSG_NOSIGNAL
Definition: platform_osx.h:53
void SafeSleepMs(const unsigned ms)
Definition: posix.cc:1913
bool DiffTree(const std::string &path_a, const std::string &path_b)
Definition: posix.cc:594
void SortTeam(std::vector< T > *tractor, std::vector< U > *towed)
Definition: algorithm.h:51
static std::string ToString(const Names name)
Definition: posix.cc:1742
void Block2Nonblock(int filedes)
Definition: posix.cc:680
unsigned GetLength() const
Definition: shortstring.h:104
bool IsAbsolutePath(const std::string &path)
Definition: posix.cc:191
bool ProcessExists(pid_t pid)
Definition: posix.cc:1576
std::string MakeCanonicalPath(const std::string &path)
Definition: posix.cc:96
const char * GetChars() const
Definition: shortstring.h:96
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:534
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1085
void ReadPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:546
std::vector< std::string > FindFilesBySuffix(const std::string &dir, const std::string &suffix)
Definition: posix.cc:1149
void ClosePipe(int pipe_fd[2])
Definition: posix.cc:584
bool IsMountPoint(const std::string &path)
Definition: posix.cc:299
int RecvFdFromSocket(int msg_fd)
Definition: posix.cc:741
bool SafeWriteV(int fd, struct iovec *iov, unsigned iovcnt)
Definition: posix.cc:1942
void UnlockFile(const int filedes)
Definition: posix.cc:1020
void BlockSignal(int signum)
Definition: posix.cc:1588
struct dirent64 platform_dirent64