/ src / ipc / process.cpp
process.cpp
 1  // Copyright (c) 2021-2022 The Bitcoin Core developers
 2  // Distributed under the MIT software license, see the accompanying
 3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 4  
 5  #include <ipc/process.h>
 6  #include <ipc/protocol.h>
 7  #include <mp/util.h>
 8  #include <tinyformat.h>
 9  #include <util/fs.h>
10  #include <util/strencodings.h>
11  
12  #include <cstdint>
13  #include <cstdlib>
14  #include <exception>
15  #include <iostream>
16  #include <stdexcept>
17  #include <string.h>
18  #include <system_error>
19  #include <unistd.h>
20  #include <utility>
21  #include <vector>
22  
23  namespace ipc {
24  namespace {
25  class ProcessImpl : public Process
26  {
27  public:
28      int spawn(const std::string& new_exe_name, const fs::path& argv0_path, int& pid) override
29      {
30          return mp::SpawnProcess(pid, [&](int fd) {
31              fs::path path = argv0_path;
32              path.remove_filename();
33              path /= fs::PathFromString(new_exe_name);
34              return std::vector<std::string>{fs::PathToString(path), "-ipcfd", strprintf("%i", fd)};
35          });
36      }
37      int waitSpawned(int pid) override { return mp::WaitProcess(pid); }
38      bool checkSpawned(int argc, char* argv[], int& fd) override
39      {
40          // If this process was not started with a single -ipcfd argument, it is
41          // not a process spawned by the spawn() call above, so return false and
42          // do not try to serve requests.
43          if (argc != 3 || strcmp(argv[1], "-ipcfd") != 0) {
44              return false;
45          }
46          // If a single -ipcfd argument was provided, return true and get the
47          // file descriptor so Protocol::serve() can be called to handle
48          // requests from the parent process. The -ipcfd argument is not valid
49          // in combination with other arguments because the parent process
50          // should be able to control the child process through the IPC protocol
51          // without passing information out of band.
52          if (!ParseInt32(argv[2], &fd)) {
53              throw std::runtime_error(strprintf("Invalid -ipcfd number '%s'", argv[2]));
54          }
55          return true;
56      }
57  };
58  } // namespace
59  
60  std::unique_ptr<Process> MakeProcess() { return std::make_unique<ProcessImpl>(); }
61  } // namespace ipc