1 // mongo/shell/shell_utils_launcher.h
2 
3 /**
4  *    Copyright (C) 2018-present MongoDB, Inc.
5  *
6  *    This program is free software: you can redistribute it and/or modify
7  *    it under the terms of the Server Side Public License, version 1,
8  *    as published by MongoDB, Inc.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    Server Side Public License for more details.
14  *
15  *    You should have received a copy of the Server Side Public License
16  *    along with this program. If not, see
17  *    <http://www.mongodb.com/licensing/server-side-public-license>.
18  *
19  *    As a special exception, the copyright holders give permission to link the
20  *    code of portions of this program with the OpenSSL library under certain
21  *    conditions as described in each individual source file and distribute
22  *    linked combinations including the program with the OpenSSL library. You
23  *    must comply with the Server Side Public License in all respects for
24  *    all of the code used other than as permitted herein. If you modify file(s)
25  *    with this exception, you may extend this exception to your version of the
26  *    file(s), but you are not obligated to do so. If you do not wish to do so,
27  *    delete this exception statement from your version. If you delete this
28  *    exception statement from all source files in the program, then also delete
29  *    it in the license file.
30  */
31 
32 #pragma once
33 
34 #include <boost/filesystem/convenience.hpp>
35 #include <map>
36 #include <sstream>
37 #include <string>
38 #include <utility>
39 #include <vector>
40 
41 #include "mongo/bson/bsonobj.h"
42 #include "mongo/platform/process_id.h"
43 #include "mongo/platform/unordered_map.h"
44 #include "mongo/platform/unordered_set.h"
45 #include "mongo/stdx/mutex.h"
46 #include "mongo/stdx/thread.h"
47 
48 namespace mongo {
49 
50 class Scope;
51 
52 namespace shell_utils {
53 
54 // Scoped management of mongo program instances.  Simple implementation:
55 // destructor kills all mongod instances created by the shell.
56 struct MongoProgramScope {
MongoProgramScopeMongoProgramScope57     MongoProgramScope() {}  // Avoid 'unused variable' warning.
58     ~MongoProgramScope();
59 };
60 int KillMongoProgramInstances();
61 
62 // Returns true if there are running child processes.
63 std::vector<ProcessId> getRunningMongoChildProcessIds();
64 
65 void installShellUtilsLauncher(Scope& scope);
66 
67 /** Record log lines from concurrent programs.  All public members are thread safe. */
68 class ProgramOutputMultiplexer {
69 public:
70     void appendLine(int port, ProcessId pid, const std::string& name, const std::string& line);
71     std::string str() const;
72     void clear();
73 
74 private:
75     std::stringstream _buffer;
76 };
77 
78 /**
79  * A registry of spawned programs that are identified by a bound port or else a system pid.
80  * All public member functions are thread safe.
81  */
82 class ProgramRegistry {
83 public:
84     bool isPortRegistered(int port) const;
85     /** @return pid for a registered port. */
86     ProcessId pidForPort(int port) const;
87     /** @return port (-1 if doesn't exist) for a registered pid. */
88     int portForPid(ProcessId pid) const;
89     /** Register an unregistered program. */
90     void registerProgram(ProcessId pid, int port = -1);
91     /** Registers the reader thread for the PID. Must be called before `joinReaderThread`. */
92     void registerReaderThread(ProcessId pid, stdx::thread reader);
93     /** Closes the registered program's write pipe and waits for all of the written output to be
94      * consumed by the reader thread, then removes the program from the registry */
95     void unregisterProgram(ProcessId pid);
96 
97     bool isPidRegistered(ProcessId pid) const;
98     void getRegisteredPorts(std::vector<int>& ports);
99     void getRegisteredPids(std::vector<ProcessId>& pids);
100 
101 private:
102     stdx::unordered_set<ProcessId> _registeredPids;
103     stdx::unordered_map<int, ProcessId> _portToPidMap;
104     stdx::unordered_map<ProcessId, stdx::thread> _outputReaderThreads;
105     mutable stdx::recursive_mutex _mutex;
106 
107 #ifdef _WIN32
108 private:
109     std::map<ProcessId, HANDLE> _handles;
110 
111 public:
112     HANDLE getHandleForPid(ProcessId pid);
113     void eraseHandleForPid(ProcessId pid);
114     std::size_t countHandleForPid(ProcessId pid);
115     void insertHandleForPid(ProcessId pid, HANDLE handle);
116 
117 #endif
118 };
119 
120 /** Helper class for launching a program and logging its output. */
121 class ProgramRunner {
122 public:
123     /** @param args The program's arguments, including the program name.
124      *  @param env Environment to run the program with, which will override any set by the local
125      *             environment
126      * @param isMongo Indicator variable, true if runs as a mongo process.
127      */
128     ProgramRunner(const BSONObj& args, const BSONObj& env, bool isMongo);
129     /** Launch the program. */
130     void start();
131     /** Continuously read the program's output, generally from a special purpose thread. */
132     void operator()();
pid()133     ProcessId pid() const {
134         return _pid;
135     }
port()136     int port() const {
137         return _port;
138     }
139 
140 private:
141     boost::filesystem::path findProgram(const std::string& prog);
142     void launchProcess(int child_stdout);
143 
144     std::vector<std::string> _argv;
145     std::map<std::string, std::string> _envp;
146     int _port;
147     int _pipe;
148     ProcessId _pid;
149     std::string _name;
150 };
151 }
152 }
153