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