Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/atf/atf-c++/detail/process.cpp
39563 views
1
// Copyright (c) 2008 The NetBSD Foundation, Inc.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions
6
// are met:
7
// 1. Redistributions of source code must retain the above copyright
8
// notice, this list of conditions and the following disclaimer.
9
// 2. Redistributions in binary form must reproduce the above copyright
10
// notice, this list of conditions and the following disclaimer in the
11
// documentation and/or other materials provided with the distribution.
12
//
13
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
#include "atf-c++/detail/process.hpp"
27
28
extern "C" {
29
#include <signal.h>
30
31
#include "atf-c/detail/process.h"
32
#include "atf-c/error.h"
33
}
34
35
#include <iostream>
36
37
#include "atf-c++/detail/exceptions.hpp"
38
#include "atf-c++/detail/sanity.hpp"
39
40
namespace detail = atf::process::detail;
41
namespace impl = atf::process;
42
#define IMPL_NAME "atf::process"
43
44
// ------------------------------------------------------------------------
45
// Auxiliary functions.
46
// ------------------------------------------------------------------------
47
48
template< class C >
49
atf::auto_array< const char* >
50
collection_to_argv(const C& c)
51
{
52
atf::auto_array< const char* > argv(new const char*[c.size() + 1]);
53
54
std::size_t pos = 0;
55
for (typename C::const_iterator iter = c.begin(); iter != c.end();
56
iter++) {
57
argv[pos] = (*iter).c_str();
58
pos++;
59
}
60
INV(pos == c.size());
61
argv[pos] = NULL;
62
63
return argv;
64
}
65
66
template< class C >
67
C
68
argv_to_collection(const char* const* argv)
69
{
70
C c;
71
72
for (const char* const* iter = argv; *iter != NULL; iter++)
73
c.push_back(std::string(*iter));
74
75
return c;
76
}
77
78
// ------------------------------------------------------------------------
79
// The "argv_array" type.
80
// ------------------------------------------------------------------------
81
82
impl::argv_array::argv_array(void) :
83
m_exec_argv(collection_to_argv(m_args))
84
{
85
}
86
87
impl::argv_array::argv_array(const char* arg1, ...)
88
{
89
m_args.push_back(arg1);
90
91
{
92
va_list ap;
93
const char* nextarg;
94
95
va_start(ap, arg1);
96
while ((nextarg = va_arg(ap, const char*)) != NULL)
97
m_args.push_back(nextarg);
98
va_end(ap);
99
}
100
101
ctor_init_exec_argv();
102
}
103
104
impl::argv_array::argv_array(const char* const* ca) :
105
m_args(argv_to_collection< args_vector >(ca)),
106
m_exec_argv(collection_to_argv(m_args))
107
{
108
}
109
110
impl::argv_array::argv_array(const argv_array& a) :
111
m_args(a.m_args),
112
m_exec_argv(collection_to_argv(m_args))
113
{
114
}
115
116
void
117
impl::argv_array::ctor_init_exec_argv(void)
118
{
119
m_exec_argv = collection_to_argv(m_args);
120
}
121
122
const char* const*
123
impl::argv_array::exec_argv(void)
124
const
125
{
126
return m_exec_argv.get();
127
}
128
129
impl::argv_array::size_type
130
impl::argv_array::size(void)
131
const
132
{
133
return m_args.size();
134
}
135
136
const char*
137
impl::argv_array::operator[](int idx)
138
const
139
{
140
return m_args[idx].c_str();
141
}
142
143
impl::argv_array::const_iterator
144
impl::argv_array::begin(void)
145
const
146
{
147
return m_args.begin();
148
}
149
150
impl::argv_array::const_iterator
151
impl::argv_array::end(void)
152
const
153
{
154
return m_args.end();
155
}
156
157
impl::argv_array&
158
impl::argv_array::operator=(const argv_array& a)
159
{
160
if (this != &a) {
161
m_args = a.m_args;
162
m_exec_argv = collection_to_argv(m_args);
163
}
164
return *this;
165
}
166
167
// ------------------------------------------------------------------------
168
// The "stream" types.
169
// ------------------------------------------------------------------------
170
171
impl::basic_stream::basic_stream(void) :
172
m_inited(false)
173
{
174
}
175
176
impl::basic_stream::~basic_stream(void)
177
{
178
if (m_inited)
179
atf_process_stream_fini(&m_sb);
180
}
181
182
const atf_process_stream_t*
183
impl::basic_stream::get_sb(void)
184
const
185
{
186
INV(m_inited);
187
return &m_sb;
188
}
189
190
impl::stream_capture::stream_capture(void)
191
{
192
atf_error_t err = atf_process_stream_init_capture(&m_sb);
193
if (atf_is_error(err))
194
throw_atf_error(err);
195
m_inited = true;
196
}
197
198
impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
199
{
200
atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
201
if (atf_is_error(err))
202
throw_atf_error(err);
203
m_inited = true;
204
}
205
206
impl::stream_inherit::stream_inherit(void)
207
{
208
atf_error_t err = atf_process_stream_init_inherit(&m_sb);
209
if (atf_is_error(err))
210
throw_atf_error(err);
211
m_inited = true;
212
}
213
214
impl::stream_redirect_fd::stream_redirect_fd(const int fd)
215
{
216
atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
217
if (atf_is_error(err))
218
throw_atf_error(err);
219
m_inited = true;
220
}
221
222
impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
223
{
224
atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
225
if (atf_is_error(err))
226
throw_atf_error(err);
227
m_inited = true;
228
}
229
230
// ------------------------------------------------------------------------
231
// The "status" type.
232
// ------------------------------------------------------------------------
233
234
impl::status::status(atf_process_status_t& s) :
235
m_status(s)
236
{
237
}
238
239
impl::status::~status(void)
240
{
241
atf_process_status_fini(&m_status);
242
}
243
244
bool
245
impl::status::exited(void)
246
const
247
{
248
return atf_process_status_exited(&m_status);
249
}
250
251
int
252
impl::status::exitstatus(void)
253
const
254
{
255
return atf_process_status_exitstatus(&m_status);
256
}
257
258
bool
259
impl::status::signaled(void)
260
const
261
{
262
return atf_process_status_signaled(&m_status);
263
}
264
265
int
266
impl::status::termsig(void)
267
const
268
{
269
return atf_process_status_termsig(&m_status);
270
}
271
272
bool
273
impl::status::coredump(void)
274
const
275
{
276
return atf_process_status_coredump(&m_status);
277
}
278
279
// ------------------------------------------------------------------------
280
// The "child" type.
281
// ------------------------------------------------------------------------
282
283
impl::child::child(atf_process_child_t& c) :
284
m_child(c),
285
m_waited(false)
286
{
287
}
288
289
impl::child::~child(void)
290
{
291
if (!m_waited) {
292
::kill(atf_process_child_pid(&m_child), SIGTERM);
293
294
atf_process_status_t s;
295
atf_error_t err = atf_process_child_wait(&m_child, &s);
296
INV(!atf_is_error(err));
297
atf_process_status_fini(&s);
298
}
299
}
300
301
impl::status
302
impl::child::wait(void)
303
{
304
atf_process_status_t s;
305
306
atf_error_t err = atf_process_child_wait(&m_child, &s);
307
if (atf_is_error(err))
308
throw_atf_error(err);
309
310
m_waited = true;
311
return status(s);
312
}
313
314
pid_t
315
impl::child::pid(void)
316
const
317
{
318
return atf_process_child_pid(&m_child);
319
}
320
321
int
322
impl::child::stdout_fd(void)
323
{
324
return atf_process_child_stdout(&m_child);
325
}
326
327
int
328
impl::child::stderr_fd(void)
329
{
330
return atf_process_child_stderr(&m_child);
331
}
332
333
// ------------------------------------------------------------------------
334
// Free functions.
335
// ------------------------------------------------------------------------
336
337
void
338
detail::flush_streams(void)
339
{
340
// TODO: This should only be executed when inheriting the stdout or
341
// stderr file descriptors. However, the flushing is specific to the
342
// iostreams, so we cannot do it from the C library where all the process
343
// logic is performed. Come up with a better design.
344
std::cout.flush();
345
std::cerr.flush();
346
}
347
348