Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 2: [PATCH 02/68] feat(runtime): preserve Roots operator controls on Core 30.3

src/util/subprocess.h

Before: src/util/subprocess.h · After: src/util/subprocess.h

File metadata
index 9abca911d827b4e5c124dff25f802dbf2acd8c76..7cabd1baf27c5366aea0fed3a6b6bbb4ded01475 100644

Download original patch · Release notes

Diff rows 1–171 of 171. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/util/subprocess.h CHANGED
@@ -36,6 +36,8 @@ Documentation for C++ subprocessing library.
36
  #ifndef BITCOIN_UTIL_SUBPROCESS_H
37
  #define BITCOIN_UTIL_SUBPROCESS_H
38
 
 
 
39
  #include <util/syserror.h>
40
 
41
  #include <algorithm>
@@ -536,6 +538,20 @@ namespace util
536
  * -------------------------------
537
  */
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  /*!
540
  * Base class for all arguments involving string value.
541
  */
@@ -733,6 +749,7 @@ struct ArgumentDeducer
733
  void set_option(input&& inp);
734
  void set_option(output&& out);
735
  void set_option(error&& err);
 
736
 
737
  private:
738
  Popen* popen_ = nullptr;
@@ -924,6 +941,8 @@ private:
924
  * Command provided in a single string.
925
  * wait() - Wait for the child to exit.
926
  * retcode() - The return code of the exited child.
 
 
927
  * send(...) - Send input to the input channel of the child.
928
  * communicate(...) - Get the output/error from the child and close the channels
929
  * from the parent side.
@@ -974,6 +993,12 @@ public:
974
 
975
  int wait() noexcept(false);
976
 
 
 
 
 
 
 
977
  void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }
978
 
979
  void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
@@ -1026,6 +1051,8 @@ private:
1026
  std::future<void> cleanup_future_;
1027
  #endif
1028
 
 
 
1029
  std::string exe_name_;
1030
 
1031
  // Command in string format
@@ -1034,6 +1061,7 @@ private:
1034
  std::vector<std::string> vargs_;
1035
  std::vector<char*> cargv_;
1036
 
 
1037
  // Pid of the child process
1038
  int child_pid_ = -1;
1039
 
@@ -1093,6 +1121,68 @@ inline int Popen::wait() noexcept(false)
1093
  #endif
1094
  }
1095
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1096
  inline void Popen::execute_process() noexcept(false)
1097
  {
1098
  #ifdef __USING_WINDOWS__
@@ -1200,6 +1290,8 @@ inline void Popen::execute_process() noexcept(false)
1200
  throw OSError("fork failed", errno);
1201
  }
1202
 
 
 
1203
  if (child_pid_ == 0)
1204
  {
1205
  // Close descriptors belonging to parent
@@ -1274,6 +1366,14 @@ namespace detail {
1274
  if (err.rd_ch_ != -1) popen_->stream_.err_read_ = err.rd_ch_;
1275
  }
1276
 
 
 
 
 
 
 
 
 
1277
 
1278
  inline void Child::execute_child() {
1279
  #ifndef __USING_WINDOWS__
@@ -1320,6 +1420,11 @@ namespace detail {
1320
  if (stream.err_write_ != -1 && stream.err_write_ > 2)
1321
  subprocess_close(stream.err_write_);
1322
 
 
 
 
 
 
1323
  // Replace the current image with the executable
1324
  sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data());
1325
 
 
36
  #ifndef BITCOIN_UTIL_SUBPROCESS_H
37
  #define BITCOIN_UTIL_SUBPROCESS_H
38
 
39
+ #include <util/fs.h>
40
+ #include <util/strencodings.h>
41
  #include <util/syserror.h>
42
 
43
  #include <algorithm>
 
538
  * -------------------------------
539
  */
540
 
541
+ /*!
542
+ * Option to close all file descriptors
543
+ * when the child process is spawned.
544
+ * The close fd list does not include
545
+ * input/output/error if they are explicitly
546
+ * set as part of the Popen arguments.
547
+ *
548
+ * Default value is false.
549
+ */
550
+ struct close_fds {
551
+ explicit close_fds(bool c): close_all(c) {}
552
+ bool close_all = false;
553
+ };
554
+
555
  /*!
556
  * Base class for all arguments involving string value.
557
  */
 
749
  void set_option(input&& inp);
750
  void set_option(output&& out);
751
  void set_option(error&& err);
752
+ void set_option(close_fds&& cfds);
753
 
754
  private:
755
  Popen* popen_ = nullptr;
 
941
  * Command provided in a single string.
942
  * wait() - Wait for the child to exit.
943
  * retcode() - The return code of the exited child.
944
+ * poll() - Check the status of the running child.
945
+ * kill(sig_num) - Kill the child. SIGTERM used by default.
946
  * send(...) - Send input to the input channel of the child.
947
  * communicate(...) - Get the output/error from the child and close the channels
948
  * from the parent side.
 
993
 
994
  int wait() noexcept(false);
995
 
996
+ int poll() noexcept(false);
997
+
998
+ // Does not fail, Caller is expected to recheck the
999
+ // status with a call to poll()
1000
+ void kill(int sig_num = 9);
1001
+
1002
  void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }
1003
 
1004
  void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
 
1051
  std::future<void> cleanup_future_;
1052
  #endif
1053
 
1054
+ bool close_fds_ = false;
1055
+
1056
  std::string exe_name_;
1057
 
1058
  // Command in string format
 
1061
  std::vector<std::string> vargs_;
1062
  std::vector<char*> cargv_;
1063
 
1064
+ bool child_created_ = false;
1065
  // Pid of the child process
1066
  int child_pid_ = -1;
1067
 
 
1121
  #endif
1122
  }
1123
 
1124
+ inline int Popen::poll() noexcept(false)
1125
+ {
1126
+ #ifdef __USING_WINDOWS__
1127
+ int ret = WaitForSingleObject(process_handle_, 0);
1128
+ if (ret != WAIT_OBJECT_0) return -1;
1129
+
1130
+ DWORD dretcode_;
1131
+ if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_))
1132
+ throw OSError("GetExitCodeProcess", 0);
1133
+
1134
+ retcode_ = (int)dretcode_;
1135
+ CloseHandle(process_handle_);
1136
+
1137
+ return retcode_;
1138
+ #else
1139
+ if (!child_created_) return -1; // TODO: ??
1140
+
1141
+ int status;
1142
+
1143
+ // Returns zero if child is still running
1144
+ int ret = waitpid(child_pid_, &status, WNOHANG);
1145
+ if (ret == 0) return -1;
1146
+
1147
+ if (ret == child_pid_) {
1148
+ if (WIFSIGNALED(status)) {
1149
+ retcode_ = WTERMSIG(status);
1150
+ } else if (WIFEXITED(status)) {
1151
+ retcode_ = WEXITSTATUS(status);
1152
+ } else {
1153
+ retcode_ = 255;
1154
+ }
1155
+ return retcode_;
1156
+ }
1157
+
1158
+ if (ret == -1) {
1159
+ // From subprocess.py
1160
+ // This happens if SIGCHLD is set to be ignored
1161
+ // or waiting for child process has otherwise been disabled
1162
+ // for our process. This child is dead, we cannot get the
1163
+ // status.
1164
+ if (errno == ECHILD) retcode_ = 0;
1165
+ else throw OSError("waitpid failed", errno);
1166
+ } else {
1167
+ retcode_ = ret;
1168
+ }
1169
+
1170
+ return retcode_;
1171
+ #endif
1172
+ }
1173
+
1174
+ inline void Popen::kill(int sig_num)
1175
+ {
1176
+ #ifdef __USING_WINDOWS__
1177
+ if (!TerminateProcess(this->process_handle_, (UINT)sig_num)) {
1178
+ throw OSError("TerminateProcess", 0);
1179
+ }
1180
+ #else
1181
+ ::kill(child_pid_, sig_num);
1182
+ #endif
1183
+ }
1184
+
1185
+
1186
  inline void Popen::execute_process() noexcept(false)
1187
  {
1188
  #ifdef __USING_WINDOWS__
 
1290
  throw OSError("fork failed", errno);
1291
  }
1292
 
1293
+ child_created_ = true;
1294
+
1295
  if (child_pid_ == 0)
1296
  {
1297
  // Close descriptors belonging to parent
 
1366
  if (err.rd_ch_ != -1) popen_->stream_.err_read_ = err.rd_ch_;
1367
  }
1368
 
1369
+ inline void ArgumentDeducer::set_option(close_fds&& cfds) {
1370
+ popen_->close_fds_ = cfds.close_all;
1371
+ }
1372
+
1373
+ #ifndef __USING_WINDOWS__
1374
+ void subprocess_close_all_fds(int except_fd);
1375
+ #endif
1376
+
1377
 
1378
  inline void Child::execute_child() {
1379
  #ifndef __USING_WINDOWS__
 
1420
  if (stream.err_write_ != -1 && stream.err_write_ > 2)
1421
  subprocess_close(stream.err_write_);
1422
 
1423
+ // Close all the inherited fd's except the error write pipe
1424
+ if (parent_->close_fds_) {
1425
+ subprocess_close_all_fds(/*except_fd=*/ err_wr_pipe_);
1426
+ }
1427
+
1428
  // Replace the current image with the executable
1429
  sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data());
1430