file_descriptor_shuffle.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
  5. #define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
  6. // This code exists to shuffle file descriptors, which is commonly needed when
  7. // forking subprocesses. The naive approach (just call dup2 to set up the
  8. // desired descriptors) is very simple, but wrong: it won't handle edge cases
  9. // (like mapping 0 -> 1, 1 -> 0) correctly.
  10. //
  11. // In order to unittest this code, it's broken into the abstract action (an
  12. // injective multimap) and the concrete code for dealing with file descriptors.
  13. // Users should use the code like this:
  14. // base::InjectiveMultimap file_descriptor_map;
  15. // file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true));
  16. // file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true));
  17. // file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true));
  18. // base::ShuffleFileDescriptors(file_descriptor_map);
  19. //
  20. // and trust the Right Thing will get done.
  21. #include <vector>
  22. #include "base/base_export.h"
  23. #include "base/compiler_specific.h"
  24. namespace base {
  25. // A Delegate which performs the actions required to perform an injective
  26. // multimapping in place.
  27. class InjectionDelegate {
  28. public:
  29. // Duplicate |fd|, an element of the domain, and write a fresh element of the
  30. // domain into |result|. Returns true iff successful.
  31. virtual bool Duplicate(int* result, int fd) = 0;
  32. // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff
  33. // successful.
  34. virtual bool Move(int src, int dest) = 0;
  35. // Delete an element of the domain.
  36. virtual void Close(int fd) = 0;
  37. protected:
  38. virtual ~InjectionDelegate() = default;
  39. };
  40. // An implementation of the InjectionDelegate interface using the file
  41. // descriptor table of the current process as the domain.
  42. class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate {
  43. bool Duplicate(int* result, int fd) override;
  44. bool Move(int src, int dest) override;
  45. void Close(int fd) override;
  46. };
  47. // A single arc of the directed graph which describes an injective multimapping.
  48. struct InjectionArc {
  49. InjectionArc(int in_source, int in_dest, bool in_close)
  50. : source(in_source),
  51. dest(in_dest),
  52. close(in_close) {
  53. }
  54. int source;
  55. int dest;
  56. bool close; // if true, delete the source element after performing the
  57. // mapping.
  58. };
  59. typedef std::vector<InjectionArc> InjectiveMultimap;
  60. BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map,
  61. InjectionDelegate* delegate);
  62. BASE_EXPORT bool PerformInjectiveMultimapDestructive(
  63. InjectiveMultimap* map,
  64. InjectionDelegate* delegate);
  65. // This function will not call malloc but will mutate |map|
  66. static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) {
  67. FileDescriptorTableInjection delegate;
  68. return PerformInjectiveMultimapDestructive(map, &delegate);
  69. }
  70. } // namespace base
  71. #endif // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_