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