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 29namespace base { 30 31// A Delegate which performs the actions required to perform an injective 32// multimapping in place. 33class 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. 50class 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. 57struct 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 70typedef std::vector<InjectionArc> InjectiveMultimap; 71 72BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map, 73 InjectionDelegate* delegate); 74 75BASE_EXPORT bool PerformInjectiveMultimapDestructive( 76 InjectiveMultimap* map, 77 InjectionDelegate* delegate); 78 79// This function will not call malloc but will mutate |map| 80static 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