16d528ed9Sopenharmony_ci// Copyright (c) 2011 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ 66d528ed9Sopenharmony_ci#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ 76d528ed9Sopenharmony_ci 86d528ed9Sopenharmony_ci// This code exists to shuffle file descriptors, which is commonly needed when 96d528ed9Sopenharmony_ci// forking subprocesses. The naive approach (just call dup2 to set up the 106d528ed9Sopenharmony_ci// desired descriptors) is very simple, but wrong: it won't handle edge cases 116d528ed9Sopenharmony_ci// (like mapping 0 -> 1, 1 -> 0) correctly. 126d528ed9Sopenharmony_ci// 136d528ed9Sopenharmony_ci// In order to unittest this code, it's broken into the abstract action (an 146d528ed9Sopenharmony_ci// injective multimap) and the concrete code for dealing with file descriptors. 156d528ed9Sopenharmony_ci// Users should use the code like this: 166d528ed9Sopenharmony_ci// base::InjectiveMultimap file_descriptor_map; 176d528ed9Sopenharmony_ci// file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true)); 186d528ed9Sopenharmony_ci// file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true)); 196d528ed9Sopenharmony_ci// file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true)); 206d528ed9Sopenharmony_ci// base::ShuffleFileDescriptors(file_descriptor_map); 216d528ed9Sopenharmony_ci// 226d528ed9Sopenharmony_ci// and trust the the Right Thing will get done. 236d528ed9Sopenharmony_ci 246d528ed9Sopenharmony_ci#include <vector> 256d528ed9Sopenharmony_ci 266d528ed9Sopenharmony_ci#include "base/compiler_specific.h" 276d528ed9Sopenharmony_ci 286d528ed9Sopenharmony_cinamespace base { 296d528ed9Sopenharmony_ci 306d528ed9Sopenharmony_ci// A Delegate which performs the actions required to perform an injective 316d528ed9Sopenharmony_ci// multimapping in place. 326d528ed9Sopenharmony_ciclass InjectionDelegate { 336d528ed9Sopenharmony_ci public: 346d528ed9Sopenharmony_ci // Duplicate |fd|, an element of the domain, and write a fresh element of the 356d528ed9Sopenharmony_ci // domain into |result|. Returns true iff successful. 366d528ed9Sopenharmony_ci virtual bool Duplicate(int* result, int fd) = 0; 376d528ed9Sopenharmony_ci // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff 386d528ed9Sopenharmony_ci // successful. 396d528ed9Sopenharmony_ci virtual bool Move(int src, int dest) = 0; 406d528ed9Sopenharmony_ci // Delete an element of the domain. 416d528ed9Sopenharmony_ci virtual void Close(int fd) = 0; 426d528ed9Sopenharmony_ci 436d528ed9Sopenharmony_ci protected: 446d528ed9Sopenharmony_ci virtual ~InjectionDelegate() = default; 456d528ed9Sopenharmony_ci}; 466d528ed9Sopenharmony_ci 476d528ed9Sopenharmony_ci// An implementation of the InjectionDelegate interface using the file 486d528ed9Sopenharmony_ci// descriptor table of the current process as the domain. 496d528ed9Sopenharmony_ciclass FileDescriptorTableInjection : public InjectionDelegate { 506d528ed9Sopenharmony_ci bool Duplicate(int* result, int fd) override; 516d528ed9Sopenharmony_ci bool Move(int src, int dest) override; 526d528ed9Sopenharmony_ci void Close(int fd) override; 536d528ed9Sopenharmony_ci}; 546d528ed9Sopenharmony_ci 556d528ed9Sopenharmony_ci// A single arc of the directed graph which describes an injective multimapping. 566d528ed9Sopenharmony_cistruct InjectionArc { 576d528ed9Sopenharmony_ci InjectionArc(int in_source, int in_dest, bool in_close) 586d528ed9Sopenharmony_ci : source(in_source), dest(in_dest), close(in_close) {} 596d528ed9Sopenharmony_ci 606d528ed9Sopenharmony_ci int source; 616d528ed9Sopenharmony_ci int dest; 626d528ed9Sopenharmony_ci bool close; // if true, delete the source element after performing the 636d528ed9Sopenharmony_ci // mapping. 646d528ed9Sopenharmony_ci}; 656d528ed9Sopenharmony_ci 666d528ed9Sopenharmony_citypedef std::vector<InjectionArc> InjectiveMultimap; 676d528ed9Sopenharmony_ci 686d528ed9Sopenharmony_cibool PerformInjectiveMultimap(const InjectiveMultimap& map, 696d528ed9Sopenharmony_ci InjectionDelegate* delegate); 706d528ed9Sopenharmony_ci 716d528ed9Sopenharmony_cibool PerformInjectiveMultimapDestructive(InjectiveMultimap* map, 726d528ed9Sopenharmony_ci InjectionDelegate* delegate); 736d528ed9Sopenharmony_ci 746d528ed9Sopenharmony_ci// This function will not call malloc but will mutate |map| 756d528ed9Sopenharmony_cistatic inline bool ShuffleFileDescriptors(InjectiveMultimap* map) { 766d528ed9Sopenharmony_ci FileDescriptorTableInjection delegate; 776d528ed9Sopenharmony_ci return PerformInjectiveMultimapDestructive(map, &delegate); 786d528ed9Sopenharmony_ci} 796d528ed9Sopenharmony_ci 806d528ed9Sopenharmony_ci} // namespace base 816d528ed9Sopenharmony_ci 826d528ed9Sopenharmony_ci#endif // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ 83