file_descriptor_shuffle.h revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
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 27namespace base { 28 29// A Delegate which performs the actions required to perform an injective 30// multimapping in place. 31class 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. 48class FileDescriptorTableInjection : public InjectionDelegate { 49 bool Duplicate(int* result, int fd); 50 bool Move(int src, int dest); 51 void Close(int fd); 52}; 53 54// A single arc of the directed graph which describes an injective multimapping. 55struct 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 68typedef std::vector<InjectionArc> InjectiveMultimap; 69 70bool PerformInjectiveMultimap(const InjectiveMultimap& map, 71 InjectionDelegate* delegate); 72 73bool PerformInjectiveMultimapDestructive(InjectiveMultimap* map, 74 InjectionDelegate* delegate); 75 76// This function will not call malloc but will mutate |map| 77static 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