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