v29.4-roots.2 · Commit 2: [PATCH 02/21] runtime: preserve shared operator controls
src/util/subprocess.h
Before: src/util/subprocess.h · After: src/util/subprocess.h
File metadata
index 3449fa3b1bacce60422267110b27e54b13b19458..7cabd1baf27c5366aea0fed3a6b6bbb4ded01475 100644
Download original patch · Release notes
Diff rows 1–400 of 478. 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>
|
|
@@ -65,13 +67,9 @@ Documentation for C++ subprocessing library.
|
|
|
65
67
|
|
|
66
68
|
extern "C" {
|
|
67
69
|
#ifdef __USING_WINDOWS__
|
|
68
|
-
#include <Windows.h>
|
|
70
|
+
#include <windows.h>
|
|
69
71
|
#include <io.h>
|
|
70
72
|
#include <cwchar>
|
|
71
|
-
|
|
72
|
-
#define close _close
|
|
73
|
-
#define open _open
|
|
74
|
-
#define fileno _fileno
|
|
75
73
|
#else
|
|
76
74
|
#include <sys/wait.h>
|
|
77
75
|
#include <unistd.h>
|
|
@@ -81,6 +79,22 @@ extern "C" {
|
|
|
81
79
|
#include <sys/types.h>
|
|
82
80
|
}
|
|
83
81
|
|
|
82
|
+
// The Microsoft C++ compiler issues deprecation warnings
|
|
83
|
+
// for the standard POSIX function names.
|
|
84
|
+
// Its preferred implementations have a leading underscore.
|
|
85
|
+
// See: https://learn.microsoft.com/en-us/cpp/c-runtime-library/compatibility.
|
|
86
|
+
#if (defined _MSC_VER)
|
|
87
|
+
#define subprocess_close _close
|
|
88
|
+
#define subprocess_fileno _fileno
|
|
89
|
+
#define subprocess_open _open
|
|
90
|
+
#define subprocess_write _write
|
|
91
|
+
#else
|
|
92
|
+
#define subprocess_close close
|
|
93
|
+
#define subprocess_fileno fileno
|
|
94
|
+
#define subprocess_open open
|
|
95
|
+
#define subprocess_write write
|
|
96
|
+
#endif
|
|
97
|
+
|
|
84
98
|
/*!
|
|
85
99
|
* Getting started with reading this source code.
|
|
86
100
|
* The source is mainly divided into four parts:
|
|
@@ -159,6 +173,7 @@ public:
|
|
|
159
173
|
//--------------------------------------------------------------------
|
|
160
174
|
namespace util
|
|
161
175
|
{
|
|
176
|
+
#ifdef __USING_WINDOWS__
|
|
162
177
|
inline void quote_argument(const std::wstring &argument, std::wstring &command_line,
|
|
163
178
|
bool force)
|
|
164
179
|
{
|
|
@@ -169,7 +184,7 @@ namespace util
|
|
|
169
184
|
//
|
|
170
185
|
|
|
171
186
|
if (force == false && argument.empty() == false &&
|
|
172
|
-
argument.find_first_of(L" \t\n\v\"") == argument.npos) {
|
|
187
|
+
argument.find_first_of(L" \t\n\v") == argument.npos) {
|
|
173
188
|
command_line.append(argument);
|
|
174
189
|
}
|
|
175
190
|
else {
|
|
@@ -219,7 +234,6 @@ namespace util
|
|
|
219
234
|
}
|
|
220
235
|
}
|
|
221
236
|
|
|
222
|
-
#ifdef __USING_WINDOWS__
|
|
223
237
|
inline std::string get_last_error(DWORD errorMessageID)
|
|
224
238
|
{
|
|
225
239
|
if (errorMessageID == 0)
|
|
@@ -264,7 +278,7 @@ namespace util
|
|
|
264
278
|
|
|
265
279
|
FILE *fp = _fdopen(os_fhandle, mode);
|
|
266
280
|
if (fp == 0) {
|
|
267
|
-
_close(os_fhandle);
|
|
281
|
+
subprocess_close(os_fhandle);
|
|
268
282
|
throw OSError("_fdopen", 0);
|
|
269
283
|
}
|
|
270
284
|
|
|
@@ -334,10 +348,14 @@ namespace util
|
|
|
334
348
|
void set_clo_on_exec(int fd, bool set = true)
|
|
335
349
|
{
|
|
336
350
|
int flags = fcntl(fd, F_GETFD, 0);
|
|
351
|
+
if (flags == -1) {
|
|
352
|
+
throw OSError("fcntl F_GETFD failed", errno);
|
|
353
|
+
}
|
|
337
354
|
if (set) flags |= FD_CLOEXEC;
|
|
338
355
|
else flags &= ~FD_CLOEXEC;
|
|
339
|
-
//TODO: should check for errors
|
|
340
|
-
fcntl(fd, F_SETFD, flags);
|
|
356
|
+
if (fcntl(fd, F_SETFD, flags) == -1) {
|
|
357
|
+
throw OSError("fcntl F_SETFD failed", errno);
|
|
358
|
+
}
|
|
341
359
|
}
|
|
342
360
|
|
|
343
361
|
|
|
@@ -383,7 +401,7 @@ namespace util
|
|
|
383
401
|
{
|
|
384
402
|
size_t nwritten = 0;
|
|
385
403
|
while (nwritten < length) {
|
|
386
|
-
int written = write(fd, buf + nwritten, length - nwritten);
|
|
404
|
+
int written = subprocess_write(fd, buf + nwritten, length - nwritten);
|
|
387
405
|
if (written == -1) return -1;
|
|
388
406
|
nwritten += written;
|
|
389
407
|
}
|
|
@@ -411,7 +429,7 @@ namespace util
|
|
|
411
429
|
#ifdef __USING_WINDOWS__
|
|
412
430
|
return (int)fread(buf, 1, read_upto, fp);
|
|
413
431
|
#else
|
|
414
|
-
int fd = fileno(fp);
|
|
432
|
+
int fd = subprocess_fileno(fp);
|
|
415
433
|
int rbytes = 0;
|
|
416
434
|
int eintr_cnter = 0;
|
|
417
435
|
|
|
@@ -520,6 +538,20 @@ namespace util
|
|
|
520
538
|
* -------------------------------
|
|
521
539
|
*/
|
|
522
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
|
+
|
|
523
555
|
/*!
|
|
524
556
|
* Base class for all arguments involving string value.
|
|
525
557
|
*/
|
|
@@ -527,7 +559,7 @@ struct string_arg
|
|
|
527
559
|
{
|
|
528
560
|
string_arg(const char* arg): arg_value(arg) {}
|
|
529
561
|
string_arg(std::string&& arg): arg_value(std::move(arg)) {}
|
|
530
|
-
string_arg(std::string arg): arg_value(std::move(arg)) {}
|
|
562
|
+
string_arg(const std::string& arg): arg_value(arg) {}
|
|
531
563
|
std::string arg_value;
|
|
532
564
|
};
|
|
533
565
|
|
|
@@ -573,10 +605,10 @@ struct input
|
|
|
573
605
|
explicit input(int fd): rd_ch_(fd) {}
|
|
574
606
|
|
|
575
607
|
// FILE pointer.
|
|
576
|
-
explicit input (FILE* fp):input(fileno(fp)) { assert(fp); }
|
|
608
|
+
explicit input (FILE* fp):input(subprocess_fileno(fp)) { assert(fp); }
|
|
577
609
|
|
|
578
610
|
explicit input(const char* filename) {
|
|
579
|
-
int fd = open(filename, O_RDONLY);
|
|
611
|
+
int fd = subprocess_open(filename, O_RDONLY);
|
|
580
612
|
if (fd == -1) throw OSError("File not found: ", errno);
|
|
581
613
|
rd_ch_ = fd;
|
|
582
614
|
}
|
|
@@ -606,10 +638,10 @@ struct output
|
|
|
606
638
|
{
|
|
607
639
|
explicit output(int fd): wr_ch_(fd) {}
|
|
608
640
|
|
|
609
|
-
explicit output (FILE* fp):output(fileno(fp)) { assert(fp); }
|
|
641
|
+
explicit output (FILE* fp):output(subprocess_fileno(fp)) { assert(fp); }
|
|
610
642
|
|
|
611
643
|
explicit output(const char* filename) {
|
|
612
|
-
int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
|
644
|
+
int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
|
613
645
|
if (fd == -1) throw OSError("File not found: ", errno);
|
|
614
646
|
wr_ch_ = fd;
|
|
615
647
|
}
|
|
@@ -637,10 +669,10 @@ struct error
|
|
|
637
669
|
{
|
|
638
670
|
explicit error(int fd): wr_ch_(fd) {}
|
|
639
671
|
|
|
640
|
-
explicit error(FILE* fp):error(fileno(fp)) { assert(fp); }
|
|
672
|
+
explicit error(FILE* fp):error(subprocess_fileno(fp)) { assert(fp); }
|
|
641
673
|
|
|
642
674
|
explicit error(const char* filename) {
|
|
643
|
-
int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
|
675
|
+
int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
|
|
644
676
|
if (fd == -1) throw OSError("File not found: ", errno);
|
|
645
677
|
wr_ch_ = fd;
|
|
646
678
|
}
|
|
@@ -717,6 +749,7 @@ struct ArgumentDeducer
|
|
|
717
749
|
void set_option(input&& inp);
|
|
718
750
|
void set_option(output&& out);
|
|
719
751
|
void set_option(error&& err);
|
|
752
|
+
void set_option(close_fds&& cfds);
|
|
720
753
|
|
|
721
754
|
private:
|
|
722
755
|
Popen* popen_ = nullptr;
|
|
@@ -758,7 +791,10 @@ class Communication
|
|
|
758
791
|
public:
|
|
759
792
|
Communication(Streams* stream): stream_(stream)
|
|
760
793
|
{}
|
|
761
|
-
void operator=(const Communication&) = delete;
|
|
794
|
+
Communication(const Communication&) = delete;
|
|
795
|
+
Communication& operator=(const Communication&) = delete;
|
|
796
|
+
Communication(Communication&&) = default;
|
|
797
|
+
Communication& operator=(Communication&&) = default;
|
|
762
798
|
public:
|
|
763
799
|
int send(const char* msg, size_t length);
|
|
764
800
|
int send(const std::vector<char>& msg);
|
|
@@ -795,7 +831,10 @@ class Streams
|
|
|
795
831
|
{
|
|
796
832
|
public:
|
|
797
833
|
Streams():comm_(this) {}
|
|
798
|
-
void operator=(const Streams&) = delete;
|
|
834
|
+
Streams(const Streams&) = delete;
|
|
835
|
+
Streams& operator=(const Streams&) = delete;
|
|
836
|
+
Streams(Streams&&) = default;
|
|
837
|
+
Streams& operator=(Streams&&) = default;
|
|
799
838
|
|
|
800
839
|
public:
|
|
801
840
|
void setup_comm_channels();
|
|
@@ -803,28 +842,28 @@ public:
|
|
|
803
842
|
void cleanup_fds()
|
|
804
843
|
{
|
|
805
844
|
if (write_to_child_ != -1 && read_from_parent_ != -1) {
|
|
806
|
-
close(write_to_child_);
|
|
845
|
+
subprocess_close(write_to_child_);
|
|
807
846
|
}
|
|
808
847
|
if (write_to_parent_ != -1 && read_from_child_ != -1) {
|
|
809
|
-
close(read_from_child_);
|
|
848
|
+
subprocess_close(read_from_child_);
|
|
810
849
|
}
|
|
811
850
|
if (err_write_ != -1 && err_read_ != -1) {
|
|
812
|
-
close(err_read_);
|
|
851
|
+
subprocess_close(err_read_);
|
|
813
852
|
}
|
|
814
853
|
}
|
|
815
854
|
|
|
816
855
|
void close_parent_fds()
|
|
817
856
|
{
|
|
818
|
-
if (write_to_child_ != -1) close(write_to_child_);
|
|
819
|
-
if (read_from_child_ != -1) close(read_from_child_);
|
|
820
|
-
if (err_read_ != -1) close(err_read_);
|
|
857
|
+
if (write_to_child_ != -1) subprocess_close(write_to_child_);
|
|
858
|
+
if (read_from_child_ != -1) subprocess_close(read_from_child_);
|
|
859
|
+
if (err_read_ != -1) subprocess_close(err_read_);
|
|
821
860
|
}
|
|
822
861
|
|
|
823
862
|
void close_child_fds()
|
|
824
863
|
{
|
|
825
|
-
if (write_to_parent_ != -1) close(write_to_parent_);
|
|
826
|
-
if (read_from_parent_ != -1) close(read_from_parent_);
|
|
827
|
-
if (err_write_ != -1) close(err_write_);
|
|
864
|
+
if (write_to_parent_ != -1) subprocess_close(write_to_parent_);
|
|
865
|
+
if (read_from_parent_ != -1) subprocess_close(read_from_parent_);
|
|
866
|
+
if (err_write_ != -1) subprocess_close(err_write_);
|
|
828
867
|
}
|
|
829
868
|
|
|
830
869
|
FILE* input() { return input_.get(); }
|
|
@@ -902,6 +941,8 @@ private:
|
|
|
902
941
|
* Command provided in a single string.
|
|
903
942
|
* wait() - Wait for the child to exit.
|
|
904
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.
|
|
905
946
|
* send(...) - Send input to the input channel of the child.
|
|
906
947
|
* communicate(...) - Get the output/error from the child and close the channels
|
|
907
948
|
* from the parent side.
|
|
@@ -952,6 +993,12 @@ public:
|
|
|
952
993
|
|
|
953
994
|
int wait() noexcept(false);
|
|
954
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
|
+
|
|
955
1002
|
void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }
|
|
956
1003
|
|
|
957
1004
|
void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
|
|
@@ -1004,6 +1051,8 @@ private:
|
|
|
1004
1051
|
std::future<void> cleanup_future_;
|
|
1005
1052
|
#endif
|
|
1006
1053
|
|
|
1054
|
+
bool close_fds_ = false;
|
|
1055
|
+
|
|
1007
1056
|
std::string exe_name_;
|
|
1008
1057
|
|
|
1009
1058
|
// Command in string format
|
|
@@ -1012,6 +1061,7 @@ private:
|
|
|
1012
1061
|
std::vector<std::string> vargs_;
|
|
1013
1062
|
std::vector<char*> cargv_;
|
|
1014
1063
|
|
|
1064
|
+
bool child_created_ = false;
|
|
1015
1065
|
// Pid of the child process
|
|
1016
1066
|
int child_pid_ = -1;
|
|
1017
1067
|
|
|
@@ -1043,7 +1093,19 @@ inline int Popen::wait() noexcept(false)
|
|
|
1043
1093
|
#ifdef __USING_WINDOWS__
|
|
1044
1094
|
int ret = WaitForSingleObject(process_handle_, INFINITE);
|
|
1045
1095
|
|
|
1046
|
-
return 0;
|
|
1096
|
+
// WaitForSingleObject with INFINITE should only return when process has signaled
|
|
1097
|
+
if (ret != WAIT_OBJECT_0) {
|
|
1098
|
+
throw OSError("Unexpected return code from WaitForSingleObject", 0);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
DWORD dretcode_;
|
|
1102
|
+
|
|
1103
|
+
if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_))
|
|
1104
|
+
throw OSError("Failed during call to GetExitCodeProcess", 0);
|
|
1105
|
+
|
|
1106
|
+
CloseHandle(process_handle_);
|
|
1107
|
+
|
|
1108
|
+
return (int)dretcode_;
|
|
1047
1109
|
#else
|
|
1048
1110
|
int ret, status;
|
|
1049
1111
|
std::tie(ret, status) = util::wait_for_child_exit(child_pid_);
|
|
@@ -1059,6 +1121,68 @@ inline int Popen::wait() noexcept(false)
|
|
|
1059
1121
|
#endif
|
|
1060
1122
|
}
|
|
1061
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
|
+
|
|
1062
1186
|
inline void Popen::execute_process() noexcept(false)
|
|
1063
1187
|
{
|
|
1064
1188
|
#ifdef __USING_WINDOWS__
|
|
@@ -1071,11 +1195,16 @@ inline void Popen::execute_process() noexcept(false)
|
|
|
1071
1195
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
|
1072
1196
|
std::wstring argument;
|
|
1073
1197
|
std::wstring command_line;
|
|
1198
|
+
bool first_arg = true;
|
|
1074
1199
|
|
|
1075
1200
|
for (auto arg : this->vargs_) {
|
|
1201
|
+
if (!first_arg) {
|
|
1202
|
+
command_line += L" ";
|
|
1203
|
+
} else {
|
|
1204
|
+
first_arg = false;
|
|
1205
|
+
}
|
|
1076
1206
|
argument = converter.from_bytes(arg);
|
|
1077
1207
|
util::quote_argument(argument, command_line, false);
|
|
1078
|
-
command_line += L" ";
|
|
1079
1208
|
}
|
|
1080
1209
|
|
|
1081
1210
|
// CreateProcessW can modify szCmdLine so we allocate needed memory
|
|
@@ -1156,36 +1285,40 @@ inline void Popen::execute_process() noexcept(false)
|
|
|
1156
1285
|
child_pid_ = fork();
|
|
1157
1286
|
|
|
1158
1287
|
if (child_pid_ < 0) {
|
|
1159
|
-
close(err_rd_pipe);
|
|
1160
|
-
close(err_wr_pipe);
|
|
1288
|
+
subprocess_close(err_rd_pipe);
|
|
1289
|
+
subprocess_close(err_wr_pipe);
|
|
1161
1290
|
throw OSError("fork failed", errno);
|
|
1162
1291
|
}
|
|
1163
1292
|
|
|
1293
|
+
child_created_ = true;
|
|
1294
|
+
|
|
1164
1295
|
if (child_pid_ == 0)
|
|
1165
1296
|
{
|
|
1166
1297
|
// Close descriptors belonging to parent
|
|
1167
1298
|
stream_.close_parent_fds();
|
|
1168
1299
|
|
|
1169
1300
|
//Close the read end of the error pipe
|
|
1170
|
-
close(err_rd_pipe);
|
|
1301
|
+
subprocess_close(err_rd_pipe);
|
|
1171
1302
|
|
|
1172
1303
|
detail::Child chld(this, err_wr_pipe);
|
|
1173
1304
|
chld.execute_child();
|
|
1174
1305
|
}
|