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