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. The two line-number columns refer to before and after.
src/util/subprocess.h
CHANGED
|
@@ -36,6 +36,8 @@ Documentation for C++ subprocessing library.
|
|
|
36
36
|
#ifndef BITCOIN_UTIL_SUBPROCESS_H
|
|
37
37
|
#define BITCOIN_UTIL_SUBPROCESS_H
|
|
38
38
|
|
|
39
|
+
#include <util/fs.h>
|
|
40
|
+
#include <util/strencodings.h>
|
|
39
41
|
#include <util/syserror.h>
|
|
40
42
|
|
|
41
43
|
#include <algorithm>
|
|
@@ -536,6 +538,20 @@ namespace util
|
|
|
536
538
|
* -------------------------------
|
|
537
539
|
*/
|
|
538
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
|
+
|
|
539
555
|
/*!
|
|
540
556
|
* Base class for all arguments involving string value.
|
|
541
557
|
*/
|
|
@@ -733,6 +749,7 @@ struct ArgumentDeducer
|
|
|
733
749
|
void set_option(input&& inp);
|
|
734
750
|
void set_option(output&& out);
|
|
735
751
|
void set_option(error&& err);
|
|
752
|
+
void set_option(close_fds&& cfds);
|
|
736
753
|
|
|
737
754
|
private:
|
|
738
755
|
Popen* popen_ = nullptr;
|
|
@@ -924,6 +941,8 @@ private:
|
|
|
924
941
|
* Command provided in a single string.
|
|
925
942
|
* wait() - Wait for the child to exit.
|
|
926
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.
|
|
927
946
|
* send(...) - Send input to the input channel of the child.
|
|
928
947
|
* communicate(...) - Get the output/error from the child and close the channels
|
|
929
948
|
* from the parent side.
|
|
@@ -974,6 +993,12 @@ public:
|
|
|
974
993
|
|
|
975
994
|
int wait() noexcept(false);
|
|
976
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
|
+
|
|
977
1002
|
void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }
|
|
978
1003
|
|
|
979
1004
|
void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
|
|
@@ -1026,6 +1051,8 @@ private:
|
|
|
1026
1051
|
std::future<void> cleanup_future_;
|
|
1027
1052
|
#endif
|
|
1028
1053
|
|
|
1054
|
+
bool close_fds_ = false;
|
|
1055
|
+
|
|
1029
1056
|
std::string exe_name_;
|
|
1030
1057
|
|
|
1031
1058
|
// Command in string format
|
|
@@ -1034,6 +1061,7 @@ private:
|
|
|
1034
1061
|
std::vector<std::string> vargs_;
|
|
1035
1062
|
std::vector<char*> cargv_;
|
|
1036
1063
|
|
|
1064
|
+
bool child_created_ = false;
|
|
1037
1065
|
// Pid of the child process
|
|
1038
1066
|
int child_pid_ = -1;
|
|
1039
1067
|
|
|
@@ -1093,6 +1121,68 @@ inline int Popen::wait() noexcept(false)
|
|
|
1093
1121
|
#endif
|
|
1094
1122
|
}
|
|
1095
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
|
+
|
|
1096
1186
|
inline void Popen::execute_process() noexcept(false)
|
|
1097
1187
|
{
|
|
1098
1188
|
#ifdef __USING_WINDOWS__
|
|
@@ -1200,6 +1290,8 @@ inline void Popen::execute_process() noexcept(false)
|
|
|
1200
1290
|
throw OSError("fork failed", errno);
|
|
1201
1291
|
}
|
|
1202
1292
|
|
|
1293
|
+
child_created_ = true;
|
|
1294
|
+
|
|
1203
1295
|
if (child_pid_ == 0)
|
|
1204
1296
|
{
|
|
1205
1297
|
// Close descriptors belonging to parent
|
|
@@ -1274,6 +1366,14 @@ namespace detail {
|
|
|
1274
1366
|
if (err.rd_ch_ != -1) popen_->stream_.err_read_ = err.rd_ch_;
|
|
1275
1367
|
}
|
|
1276
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
|
+
|
|
1277
1377
|
|
|
1278
1378
|
inline void Child::execute_child() {
|
|
1279
1379
|
#ifndef __USING_WINDOWS__
|
|
@@ -1320,6 +1420,11 @@ namespace detail {
|
|
|
1320
1420
|
if (stream.err_write_ != -1 && stream.err_write_ > 2)
|
|
1321
1421
|
subprocess_close(stream.err_write_);
|
|
1322
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
|
+
|
|
1323
1428
|
// Replace the current image with the executable
|
|
1324
1429
|
sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data());
|
|
1325
1430
|
|