|
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 |
|
8 // This code exists to perform the shuffling of file descriptors which is |
|
9 // commonly needed when forking subprocesses. The naive approve is very simple, |
|
10 // just call dup2 to setup the desired descriptors, but wrong. It's tough to |
|
11 // handle the edge cases (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 namespace base { |
|
27 |
|
28 // A Delegate which performs the actions required to perform an injective |
|
29 // multimapping in place. |
|
30 class InjectionDelegate { |
|
31 public: |
|
32 // Duplicate |fd|, an element of the domain, and write a fresh element of the |
|
33 // domain into |result|. Returns true iff successful. |
|
34 virtual bool Duplicate(int* result, int fd) = 0; |
|
35 // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff |
|
36 // successful. |
|
37 virtual bool Move(int src, int dest) = 0; |
|
38 // Delete an element of the domain. |
|
39 virtual void Close(int fd) = 0; |
|
40 }; |
|
41 |
|
42 // An implementation of the InjectionDelegate interface using the file |
|
43 // descriptor table of the current process as the domain. |
|
44 class FileDescriptorTableInjection : public InjectionDelegate { |
|
45 bool Duplicate(int* result, int fd); |
|
46 bool Move(int src, int dest); |
|
47 void Close(int fd); |
|
48 }; |
|
49 |
|
50 // A single arc of the directed graph which describes an injective multimapping. |
|
51 struct InjectionArc { |
|
52 InjectionArc(int in_source, int in_dest, bool in_close) |
|
53 : source(in_source), |
|
54 dest(in_dest), |
|
55 close(in_close) { |
|
56 } |
|
57 |
|
58 int source; |
|
59 int dest; |
|
60 bool close; // if true, delete the source element after performing the |
|
61 // mapping. |
|
62 }; |
|
63 |
|
64 typedef std::vector<InjectionArc> InjectiveMultimap; |
|
65 |
|
66 bool PerformInjectiveMultimap(const InjectiveMultimap& map, |
|
67 InjectionDelegate* delegate); |
|
68 bool PerformInjectiveMultimapDestructive(InjectiveMultimap* map, |
|
69 InjectionDelegate* delegate); |
|
70 |
|
71 // This function will not call malloc but will mutate |map| |
|
72 static inline bool ShuffleFileDescriptors(InjectiveMultimap *map) { |
|
73 FileDescriptorTableInjection delegate; |
|
74 return PerformInjectiveMultimapDestructive(map, &delegate); |
|
75 } |
|
76 |
|
77 } // namespace base |
|
78 |
|
79 #endif // !BASE_FILE_DESCRIPTOR_SHUFFLE_H_ |