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