Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/atf/atf-c/detail/process.c
39507 views
1
/* Copyright (c) 2007 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.h"
27
28
#include <sys/types.h>
29
#include <sys/wait.h>
30
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <stdint.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
39
#include "atf-c/defs.h"
40
#include "atf-c/detail/sanity.h"
41
#include "atf-c/error.h"
42
43
/* This prototype is not in the header file because this is a private
44
* function; however, we need to access it during testing. */
45
atf_error_t atf_process_status_init(atf_process_status_t *, int);
46
47
/* ---------------------------------------------------------------------
48
* The "stream_prepare" auxiliary type.
49
* --------------------------------------------------------------------- */
50
51
struct stream_prepare {
52
const atf_process_stream_t *m_sb;
53
54
bool m_pipefds_ok;
55
int m_pipefds[2];
56
};
57
typedef struct stream_prepare stream_prepare_t;
58
59
static
60
atf_error_t
61
stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
62
{
63
atf_error_t err;
64
65
const int type = atf_process_stream_type(sb);
66
67
sp->m_sb = sb;
68
sp->m_pipefds_ok = false;
69
70
if (type == atf_process_stream_type_capture) {
71
if (pipe(sp->m_pipefds) == -1)
72
err = atf_libc_error(errno, "Failed to create pipe");
73
else {
74
err = atf_no_error();
75
sp->m_pipefds_ok = true;
76
}
77
} else
78
err = atf_no_error();
79
80
return err;
81
}
82
83
static
84
void
85
stream_prepare_fini(stream_prepare_t *sp)
86
{
87
if (sp->m_pipefds_ok) {
88
close(sp->m_pipefds[0]);
89
close(sp->m_pipefds[1]);
90
}
91
}
92
93
/* ---------------------------------------------------------------------
94
* The "atf_process_stream" type.
95
* --------------------------------------------------------------------- */
96
97
const int atf_process_stream_type_capture = 1;
98
const int atf_process_stream_type_connect = 2;
99
const int atf_process_stream_type_inherit = 3;
100
const int atf_process_stream_type_redirect_fd = 4;
101
const int atf_process_stream_type_redirect_path = 5;
102
103
static
104
bool
105
stream_is_valid(const atf_process_stream_t *sb)
106
{
107
return (sb->m_type == atf_process_stream_type_capture) ||
108
(sb->m_type == atf_process_stream_type_connect) ||
109
(sb->m_type == atf_process_stream_type_inherit) ||
110
(sb->m_type == atf_process_stream_type_redirect_fd) ||
111
(sb->m_type == atf_process_stream_type_redirect_path);
112
}
113
114
atf_error_t
115
atf_process_stream_init_capture(atf_process_stream_t *sb)
116
{
117
sb->m_type = atf_process_stream_type_capture;
118
119
POST(stream_is_valid(sb));
120
return atf_no_error();
121
}
122
123
atf_error_t
124
atf_process_stream_init_connect(atf_process_stream_t *sb,
125
const int src_fd, const int tgt_fd)
126
{
127
PRE(src_fd >= 0);
128
PRE(tgt_fd >= 0);
129
PRE(src_fd != tgt_fd);
130
131
sb->m_type = atf_process_stream_type_connect;
132
sb->m_src_fd = src_fd;
133
sb->m_tgt_fd = tgt_fd;
134
135
POST(stream_is_valid(sb));
136
return atf_no_error();
137
}
138
139
atf_error_t
140
atf_process_stream_init_inherit(atf_process_stream_t *sb)
141
{
142
sb->m_type = atf_process_stream_type_inherit;
143
144
POST(stream_is_valid(sb));
145
return atf_no_error();
146
}
147
148
atf_error_t
149
atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
150
const int fd)
151
{
152
sb->m_type = atf_process_stream_type_redirect_fd;
153
sb->m_fd = fd;
154
155
POST(stream_is_valid(sb));
156
return atf_no_error();
157
}
158
159
atf_error_t
160
atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
161
const atf_fs_path_t *path)
162
{
163
sb->m_type = atf_process_stream_type_redirect_path;
164
sb->m_path = path;
165
166
POST(stream_is_valid(sb));
167
return atf_no_error();
168
}
169
170
void
171
atf_process_stream_fini(atf_process_stream_t *sb)
172
{
173
PRE(stream_is_valid(sb));
174
}
175
176
int
177
atf_process_stream_type(const atf_process_stream_t *sb)
178
{
179
PRE(stream_is_valid(sb));
180
181
return sb->m_type;
182
}
183
184
/* ---------------------------------------------------------------------
185
* The "atf_process_status" type.
186
* --------------------------------------------------------------------- */
187
188
atf_error_t
189
atf_process_status_init(atf_process_status_t *s, int status)
190
{
191
s->m_status = status;
192
193
return atf_no_error();
194
}
195
196
void
197
atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
198
{
199
}
200
201
bool
202
atf_process_status_exited(const atf_process_status_t *s)
203
{
204
int mutable_status = s->m_status;
205
return WIFEXITED(mutable_status);
206
}
207
208
int
209
atf_process_status_exitstatus(const atf_process_status_t *s)
210
{
211
PRE(atf_process_status_exited(s));
212
int mutable_status = s->m_status;
213
return WEXITSTATUS(mutable_status);
214
}
215
216
bool
217
atf_process_status_signaled(const atf_process_status_t *s)
218
{
219
int mutable_status = s->m_status;
220
return WIFSIGNALED(mutable_status);
221
}
222
223
int
224
atf_process_status_termsig(const atf_process_status_t *s)
225
{
226
PRE(atf_process_status_signaled(s));
227
int mutable_status = s->m_status;
228
return WTERMSIG(mutable_status);
229
}
230
231
bool
232
atf_process_status_coredump(const atf_process_status_t *s)
233
{
234
PRE(atf_process_status_signaled(s));
235
#if defined(WCOREDUMP)
236
int mutable_status = s->m_status;
237
return WCOREDUMP(mutable_status);
238
#else
239
return false;
240
#endif
241
}
242
243
/* ---------------------------------------------------------------------
244
* The "atf_process_child" type.
245
* --------------------------------------------------------------------- */
246
247
static
248
atf_error_t
249
atf_process_child_init(atf_process_child_t *c)
250
{
251
c->m_pid = 0;
252
c->m_stdout = -1;
253
c->m_stderr = -1;
254
255
return atf_no_error();
256
}
257
258
static
259
void
260
atf_process_child_fini(atf_process_child_t *c)
261
{
262
if (c->m_stdout != -1)
263
close(c->m_stdout);
264
if (c->m_stderr != -1)
265
close(c->m_stderr);
266
}
267
268
atf_error_t
269
atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
270
{
271
atf_error_t err;
272
int status;
273
274
if (waitpid(c->m_pid, &status, 0) == -1)
275
err = atf_libc_error(errno, "Failed waiting for process %d",
276
c->m_pid);
277
else {
278
atf_process_child_fini(c);
279
err = atf_process_status_init(s, status);
280
}
281
282
return err;
283
}
284
285
pid_t
286
atf_process_child_pid(const atf_process_child_t *c)
287
{
288
return c->m_pid;
289
}
290
291
int
292
atf_process_child_stdout(atf_process_child_t *c)
293
{
294
PRE(c->m_stdout != -1);
295
return c->m_stdout;
296
}
297
298
int
299
atf_process_child_stderr(atf_process_child_t *c)
300
{
301
PRE(c->m_stderr != -1);
302
return c->m_stderr;
303
}
304
305
/* ---------------------------------------------------------------------
306
* Free functions.
307
* --------------------------------------------------------------------- */
308
309
static
310
atf_error_t
311
safe_dup(const int oldfd, const int newfd)
312
{
313
atf_error_t err;
314
315
if (oldfd != newfd) {
316
if (dup2(oldfd, newfd) == -1) {
317
err = atf_libc_error(errno, "Could not allocate file descriptor");
318
} else {
319
close(oldfd);
320
err = atf_no_error();
321
}
322
} else
323
err = atf_no_error();
324
325
return err;
326
}
327
328
static
329
atf_error_t
330
child_connect(const stream_prepare_t *sp, int procfd)
331
{
332
atf_error_t err;
333
const int type = atf_process_stream_type(sp->m_sb);
334
335
if (type == atf_process_stream_type_capture) {
336
close(sp->m_pipefds[0]);
337
err = safe_dup(sp->m_pipefds[1], procfd);
338
} else if (type == atf_process_stream_type_connect) {
339
if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
340
err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
341
sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
342
else
343
err = atf_no_error();
344
} else if (type == atf_process_stream_type_inherit) {
345
err = atf_no_error();
346
} else if (type == atf_process_stream_type_redirect_fd) {
347
err = safe_dup(sp->m_sb->m_fd, procfd);
348
} else if (type == atf_process_stream_type_redirect_path) {
349
int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
350
O_WRONLY | O_CREAT | O_TRUNC, 0644);
351
if (aux == -1)
352
err = atf_libc_error(errno, "Could not create %s",
353
atf_fs_path_cstring(sp->m_sb->m_path));
354
else {
355
err = safe_dup(aux, procfd);
356
if (atf_is_error(err))
357
close(aux);
358
}
359
} else {
360
UNREACHABLE;
361
err = atf_no_error();
362
}
363
364
return err;
365
}
366
367
static
368
void
369
parent_connect(const stream_prepare_t *sp, int *fd)
370
{
371
const int type = atf_process_stream_type(sp->m_sb);
372
373
if (type == atf_process_stream_type_capture) {
374
close(sp->m_pipefds[1]);
375
*fd = sp->m_pipefds[0];
376
} else if (type == atf_process_stream_type_connect) {
377
/* Do nothing. */
378
} else if (type == atf_process_stream_type_inherit) {
379
/* Do nothing. */
380
} else if (type == atf_process_stream_type_redirect_fd) {
381
/* Do nothing. */
382
} else if (type == atf_process_stream_type_redirect_path) {
383
/* Do nothing. */
384
} else {
385
UNREACHABLE;
386
}
387
}
388
389
static
390
atf_error_t
391
do_parent(atf_process_child_t *c,
392
const pid_t pid,
393
const stream_prepare_t *outsp,
394
const stream_prepare_t *errsp)
395
{
396
atf_error_t err;
397
398
err = atf_process_child_init(c);
399
if (atf_is_error(err))
400
goto out;
401
402
c->m_pid = pid;
403
404
parent_connect(outsp, &c->m_stdout);
405
parent_connect(errsp, &c->m_stderr);
406
407
out:
408
return err;
409
}
410
411
static
412
void
413
do_child(void (*)(void *),
414
void *,
415
const stream_prepare_t *,
416
const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
417
418
static
419
void
420
do_child(void (*start)(void *),
421
void *v,
422
const stream_prepare_t *outsp,
423
const stream_prepare_t *errsp)
424
{
425
atf_error_t err;
426
427
err = child_connect(outsp, STDOUT_FILENO);
428
if (atf_is_error(err))
429
goto out;
430
431
err = child_connect(errsp, STDERR_FILENO);
432
if (atf_is_error(err))
433
goto out;
434
435
start(v);
436
UNREACHABLE;
437
438
out:
439
if (atf_is_error(err)) {
440
char buf[1024];
441
442
atf_error_format(err, buf, sizeof(buf));
443
fprintf(stderr, "Unhandled error: %s\n", buf);
444
atf_error_free(err);
445
446
exit(EXIT_FAILURE);
447
} else
448
exit(EXIT_SUCCESS);
449
}
450
451
static
452
atf_error_t
453
fork_with_streams(atf_process_child_t *c,
454
void (*start)(void *),
455
const atf_process_stream_t *outsb,
456
const atf_process_stream_t *errsb,
457
void *v)
458
{
459
atf_error_t err;
460
stream_prepare_t outsp;
461
stream_prepare_t errsp;
462
pid_t pid;
463
464
err = stream_prepare_init(&outsp, outsb);
465
if (atf_is_error(err))
466
goto out;
467
468
err = stream_prepare_init(&errsp, errsb);
469
if (atf_is_error(err))
470
goto err_outpipe;
471
472
pid = fork();
473
if (pid == -1) {
474
err = atf_libc_error(errno, "Failed to fork");
475
goto err_errpipe;
476
}
477
478
if (pid == 0) {
479
do_child(start, v, &outsp, &errsp);
480
UNREACHABLE;
481
abort();
482
err = atf_no_error();
483
} else {
484
err = do_parent(c, pid, &outsp, &errsp);
485
if (atf_is_error(err))
486
goto err_errpipe;
487
}
488
489
goto out;
490
491
err_errpipe:
492
stream_prepare_fini(&errsp);
493
err_outpipe:
494
stream_prepare_fini(&outsp);
495
496
out:
497
return err;
498
}
499
500
static
501
atf_error_t
502
init_stream_w_default(const atf_process_stream_t *usersb,
503
atf_process_stream_t *inheritsb,
504
const atf_process_stream_t **realsb)
505
{
506
atf_error_t err;
507
508
if (usersb == NULL) {
509
err = atf_process_stream_init_inherit(inheritsb);
510
if (!atf_is_error(err))
511
*realsb = inheritsb;
512
} else {
513
err = atf_no_error();
514
*realsb = usersb;
515
}
516
517
return err;
518
}
519
520
atf_error_t
521
atf_process_fork(atf_process_child_t *c,
522
void (*start)(void *),
523
const atf_process_stream_t *outsb,
524
const atf_process_stream_t *errsb,
525
void *v)
526
{
527
atf_error_t err;
528
atf_process_stream_t inherit_outsb, inherit_errsb;
529
const atf_process_stream_t *real_outsb, *real_errsb;
530
531
real_outsb = NULL; /* Shut up GCC warning. */
532
err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
533
if (atf_is_error(err))
534
goto out;
535
536
real_errsb = NULL; /* Shut up GCC warning. */
537
err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
538
if (atf_is_error(err))
539
goto out_out;
540
541
err = fork_with_streams(c, start, real_outsb, real_errsb, v);
542
543
if (errsb == NULL)
544
atf_process_stream_fini(&inherit_errsb);
545
out_out:
546
if (outsb == NULL)
547
atf_process_stream_fini(&inherit_outsb);
548
out:
549
return err;
550
}
551
552
static
553
int
554
const_execvp(const char *file, const char *const *argv)
555
{
556
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
557
return execvp(file, UNCONST(argv));
558
#undef UNCONST
559
}
560
561
static
562
atf_error_t
563
list_to_array(const atf_list_t *l, const char ***ap)
564
{
565
atf_error_t err;
566
const char **a;
567
568
a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
569
if (a == NULL)
570
err = atf_no_memory_error();
571
else {
572
const char **aiter;
573
atf_list_citer_t liter;
574
575
aiter = a;
576
atf_list_for_each_c(liter, l) {
577
*aiter = (const char *)atf_list_citer_data(liter);
578
aiter++;
579
}
580
*aiter = NULL;
581
582
err = atf_no_error();
583
*ap = a;
584
}
585
586
return err;
587
}
588
589
struct exec_args {
590
const atf_fs_path_t *m_prog;
591
const char *const *m_argv;
592
void (*m_prehook)(void);
593
};
594
595
static
596
void
597
do_exec(void *v)
598
{
599
struct exec_args *ea = v;
600
601
if (ea->m_prehook != NULL)
602
ea->m_prehook();
603
604
const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
605
const int errnocopy = errno;
606
INV(ret == -1);
607
fprintf(stderr, "exec(%s) failed: %s\n",
608
atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
609
exit(EXIT_FAILURE);
610
}
611
612
atf_error_t
613
atf_process_exec_array(atf_process_status_t *s,
614
const atf_fs_path_t *prog,
615
const char *const *argv,
616
const atf_process_stream_t *outsb,
617
const atf_process_stream_t *errsb,
618
void (*prehook)(void))
619
{
620
atf_error_t err;
621
atf_process_child_t c;
622
struct exec_args ea = { prog, argv, prehook };
623
624
PRE(outsb == NULL ||
625
atf_process_stream_type(outsb) != atf_process_stream_type_capture);
626
PRE(errsb == NULL ||
627
atf_process_stream_type(errsb) != atf_process_stream_type_capture);
628
629
err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
630
if (atf_is_error(err))
631
goto out;
632
633
again:
634
err = atf_process_child_wait(&c, s);
635
if (atf_is_error(err)) {
636
INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
637
atf_error_free(err);
638
goto again;
639
}
640
641
out:
642
return err;
643
}
644
645
atf_error_t
646
atf_process_exec_list(atf_process_status_t *s,
647
const atf_fs_path_t *prog,
648
const atf_list_t *argv,
649
const atf_process_stream_t *outsb,
650
const atf_process_stream_t *errsb,
651
void (*prehook)(void))
652
{
653
atf_error_t err;
654
const char **argv2;
655
656
PRE(outsb == NULL ||
657
atf_process_stream_type(outsb) != atf_process_stream_type_capture);
658
PRE(errsb == NULL ||
659
atf_process_stream_type(errsb) != atf_process_stream_type_capture);
660
661
argv2 = NULL; /* Silence GCC warning. */
662
err = list_to_array(argv, &argv2);
663
if (atf_is_error(err))
664
goto out;
665
666
err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
667
668
free(argv2);
669
out:
670
return err;
671
}
672
673