diff options
author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2023-04-04 22:06:18 +0200 |
---|---|---|
committer | Eugene Syromyatnikov <evgsyr@gmail.com> | 2023-04-05 09:15:53 +0200 |
commit | 787f85bae4ca460c33896599da176cc529bafaba (patch) | |
tree | fe7272dc666c4d53cf7ceea9a691aba61782635c /tests/xselect.c | |
parent | 0f7641fdf205f164db41e792b97174b3cf1812d7 (diff) | |
download | strace-787f85bae4ca460c33896599da176cc529bafaba.tar.gz |
Implement an ability to filter syscalls that operate on specific FDs
Introduce -e trace-fds= qualifier that allows specifying a set of FDs
of interest, operations on which are to be traced. Works in conjunction
(or, more specifically, inclusive disjunction) with the path tracing
functionality.
* src/defs.h: Include "number_set.h".
(tracing_fds): New external variable.
(pathtrace_match_set): Add new fdset argument to the declaration.
(pathtrace_match): Pass trace_fd_set in the new argument
to the pathtrace_match_set call.
(qualify_trace_fd): New function declaration.
* src/filter_qualify.c (trace_fd_set): New variable.
(qualify_trace_fd): New function.
(qual_options): Add various FD tracing-related items.
* src/number_set.h (trace_fd_set): New external variable declaration.
* src/pathtrace.c (pathmatch, upathmatch): Bail out if set is NULL.
(fdmatch): Add fdset argument, check fd for non-negativity and presence
in fdset if fdset is non-NULL.
(match_xselect_args): Add fdset argument, pass it to the fdmatch call.
(pathtrace_match_set): Add fdset argument, pass it to fdmatch
and match_xselect_args calls.
* src/syscall.c (syscall_entering_trace): Check tracing_fds in addition
to tracing_paths as a predicate for performing pathtrace_match check.
* src/strace.c (tracing_fds): New variable.
(init) <GETOPT_QUAL_TRACE_FD>: New enum item.
(init) <longopts>: Add"trace-fds" option.
(init) <case GETOPT_QUAL_TRACE_FD>: Call qualify_trace_fd.
(usage): Document -e trace-fds.
* doc/strace.1.in: Likewise.
* tests/.gitignore: Add dup-trace-fds-0, dup-trace-fds-0-9,
dup-trace-fds-0-P, dup-trace-fds-not-9, dup2-e-fd-0, dup2-e-fd-0-9,
dup2-e-fd-0-P, dup2-e-fd-not-9, ppoll-e-trace-fds-23,
ppoll-e-trace-fds-23-42, ppoll-e-trace-fds-not-9-42-P,
select-trace-fd-7, select-trace-fd-7-9, and select-trace-fd-7-P.
* tests/Makefile.am (check_PROGRAMS): Add ppoll-e-trace-fds-23,
ppoll-e-trace-fds-23-42, ppoll-e-trace-fds-not-9-42-P,
select-trace-fd-7, select-trace-fd-7-9, and select-trace-fd-7-P.
* tests/dup-P.c (PATH_TRACING): Set to 1.
* tests/dup2-P.c (PATH_TRACING): Likewise.
* tests/dup.c: Accommodate test for checking tracing-fds functionality.
* tests/dup2.c: Likewise.
* tests/ppoll.c: Likewise.
* tests/xselect.c: Likewise.
* tests/gen_tests.in (dup-trace-fds-0, dup-trace-fds-0-9,
dup-trace-fds-0-P, dup-trace-fds-not-9, dup2-e-fd-0, dup2-e-fd-0-9,
dup2-e-fd-0-P, dup2-e-fd-not-9, ppoll-e-trace-fds-23,
ppoll-e-trace-fds-23-42, ppoll-e-trace-fds-not-9-42-P,
select-trace-fd-7, select-trace-fd-7-9, select-trace-fd-7-P): New tests.
* tests/options-syntax.test: Add trace-fds-related option syntax checks.
* tests/pure_executables.list: Add dup-trace-fds-0, dup-trace-fds-0-9,
dup-trace-fds-0-P, dup-trace-fds-not-9, dup2-e-fd-0, dup2-e-fd-0-9,
dup2-e-fd-0-P, and dup2-e-fd-not-9.
* tests/dup-trace-fds-0-9.c: New file.
* tests/dup-trace-fds-0-P.c: Likewise.
* tests/dup-trace-fds-0.c: Likewise.
* tests/dup-trace-fds-not-9.c: Likewise.
* tests/dup2-e-fd-0-9.c: Likewise.
* tests/dup2-e-fd-0-P.c: Likewise.
* tests/dup2-e-fd-0.c: Likewise.
* tests/dup2-e-fd-not-9.c: Likewise.
* tests/ppoll-e-trace-fds-23-42.c: Likewise.
* tests/ppoll-e-trace-fds-23.c: Likewise.
* tests/ppoll-e-trace-fds-not-9-42-P.c: Likewise.
* tests/select-trace-fd-7-9.c: Likewise.
* tests/select-trace-fd-7-P.c: Likewise.
* tests/select-trace-fd-7.c: Likewise.
* NEWS: Mention it.
Suggested-by: Marty Leisner <maleisner@gmail.com>
Link: https://lists.strace.io/pipermail/strace-devel/2023-March/011209.html
Diffstat (limited to 'tests/xselect.c')
-rw-r--r-- | tests/xselect.c | 151 |
1 files changed, 97 insertions, 54 deletions
diff --git a/tests/xselect.c b/tests/xselect.c index fd7a48f03..ab53c7949 100644 --- a/tests/xselect.c +++ b/tests/xselect.c @@ -57,7 +57,21 @@ main(void) skip_if_unavailable("/proc/self/fd/"); #endif +#if defined(PATH_TRACING_FD) || defined(TRACING_FD) + static const int add_fd = +# ifdef PATH_TRACING_FD + PATH_TRACING_FD +# else + TRACING_FD +# endif + ; +#endif /* PATH_TRACING_FD || TRACING_FD */ + for (int i = 3; i < FD_SETSIZE; ++i) { +#ifdef TRACING_FD + if (i == TRACING_FD) + continue; +#endif #ifdef PATH_TRACING_FD if (i == PATH_TRACING_FD) continue; @@ -102,7 +116,7 @@ main(void) else perror_msg_and_fail(TEST_SYSCALL_STR); } -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_usec=%llu})" " = 0 (Timeout)\n", TEST_SYSCALL_STR, (long long) tv_in.tv_sec, @@ -111,7 +125,7 @@ main(void) /* EFAULT on tv argument */ XSELECT(-1, 0, 0, 0, 0, a_tv + 1); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(0, NULL, NULL, NULL, %#lx) = %s\n", TEST_SYSCALL_STR, (unsigned long) a_tv + 1, errstr); #endif @@ -122,23 +136,43 @@ main(void) for (int i = nfds; i <= smallset_size; ++i) { *l_rs = (1UL << fds[0]) | (1UL << fds[1]); XSELECT(1, i, a_rs, a_rs, a_rs, 0); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], [%d %d], NULL) = 1 ()\n", TEST_SYSCALL_STR, i, fds[0], fds[1], fds[0], fds[1], fds[0], fds[1]); -#else +#else /* PATH_TRACING_FD || TRACING_FD */ + *l_rs = (1UL << fds[0]) | (1UL << fds[1]) | (1UL << add_fd); + XSELECT(i > add_fd ? 3 : 1, i, a_rs, a_rs, a_rs, 0); + if (i > add_fd) { + printf("%s(%d, [%d %d %d], [%d %d %d], [%d %d %d]" + ", NULL) = 3 ()\n", + TEST_SYSCALL_STR, i, + fds[0], fds[1], add_fd, + fds[0], fds[1], add_fd, + fds[0], fds[1], add_fd); + } +#endif /* !PATH_TRACING_FD && !TRACING_FD */ +#if defined(PATH_TRACING_FD) && defined(TRACING_FD) *l_rs = (1UL << fds[0]) | (1UL << fds[1]) | - (1UL << PATH_TRACING_FD); - XSELECT(i > PATH_TRACING_FD ? 3 : 1, i, a_rs, a_rs, a_rs, 0); + (1UL << TRACING_FD) | (1UL << PATH_TRACING_FD); + XSELECT(1 + 2 * (!!(i > TRACING_FD) + !!(i > PATH_TRACING_FD)), + i, a_rs, a_rs, a_rs, 0); if (i > PATH_TRACING_FD) { + printf("%s(%d, [%d %d %d %d], [%d %d %d %d]" + ", [%d %d %d %d], NULL) = 5 ()\n", + TEST_SYSCALL_STR, i, + fds[0], fds[1], TRACING_FD, PATH_TRACING_FD, + fds[0], fds[1], TRACING_FD, PATH_TRACING_FD, + fds[0], fds[1], TRACING_FD, PATH_TRACING_FD); + } else if (i > TRACING_FD) { printf("%s(%d, [%d %d %d], [%d %d %d], [%d %d %d]" ", NULL) = 3 ()\n", TEST_SYSCALL_STR, i, - fds[0], fds[1], PATH_TRACING_FD, - fds[0], fds[1], PATH_TRACING_FD, - fds[0], fds[1], PATH_TRACING_FD); + fds[0], fds[1], TRACING_FD, + fds[0], fds[1], TRACING_FD, + fds[0], fds[1], TRACING_FD); } -#endif +#endif /* PATH_TRACING_FD && TRACING_FD */ } /* @@ -150,7 +184,7 @@ main(void) memcpy(tv, &tv_in, sizeof(tv_in)); rc = xselect(nfds, a_rs, a_rs, a_rs, a_tv); if (rc < 0) { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], [%d %d]" ", {tv_sec=%lld, tv_usec=%llu}) = %s\n", TEST_SYSCALL_STR, nfds, fds[0], fds[1], @@ -158,9 +192,9 @@ main(void) (long long) tv_in.tv_sec, zero_extend_signed_to_ull(tv_in.tv_usec), errstr); -#endif /* !PATH_TRACING_FD */ +#endif /* PATH_TRACING_FD && TRACING_FD */ } else { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], [%d %d]" ", {tv_sec=%lld, tv_usec=%llu}) = %ld" " (left {tv_sec=%lld, tv_usec=%llu})\n", @@ -170,7 +204,7 @@ main(void) zero_extend_signed_to_ull(tv_in.tv_usec), rc, (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec)); -#endif /* !PATH_TRACING_FD */ +#endif /* PATH_TRACING_FD && TRACING_FD */ } /* @@ -182,7 +216,7 @@ main(void) memcpy(tv, &tv_in, sizeof(tv_in)); rc = xselect(nfds, a_rs, a_rs, a_rs, a_tv); if (rc < 0) { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], [%d %d]" ", {tv_sec=%lld, tv_usec=%llu}) = %s\n", TEST_SYSCALL_STR, nfds, fds[0], fds[1], @@ -190,9 +224,9 @@ main(void) (long long) tv_in.tv_sec, zero_extend_signed_to_ull(tv_in.tv_usec), errstr); -#endif /* PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ } else { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], [%d %d]" ", {tv_sec=%lld, tv_usec=%llu}) = %ld" " (left {tv_sec=%lld, tv_usec=%llu})\n", @@ -202,7 +236,7 @@ main(void) zero_extend_signed_to_ull(tv_in.tv_usec), rc, (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec)); -#endif /* PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ } /* @@ -217,7 +251,7 @@ main(void) tv_in.tv_usec = 0xc0de2; memcpy(tv, &tv_in, sizeof(tv_in)); XSELECT(3, i, a_rs, a_ws, a_es, a_tv); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d %d %d], []" ", {tv_sec=%lld, tv_usec=%llu}) = 3 (out [1 2 %d]" ", left {tv_sec=%lld, tv_usec=%llu})\n", @@ -228,49 +262,47 @@ main(void) fds[1], (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec)); -#else - *l_rs = (1UL << fds[0]) | (1UL << fds[1]) | - (1UL << PATH_TRACING_FD); +#else /* PATH_TRACING_FD || TRACING_FD */ + *l_rs = (1UL << fds[0]) | (1UL << fds[1]) | (1UL << add_fd); *l_ws = (1UL << 1) | (1UL << 2) | (1UL << fds[0]) | (1UL << fds[1]); tv_in.tv_sec = 0xc0de1; tv_in.tv_usec = 0xc0de2; memcpy(tv, &tv_in, sizeof(tv_in)); - XSELECT(3 + (i > PATH_TRACING_FD), i, a_rs, a_ws, a_es, a_tv); - if (i > PATH_TRACING_FD) { + XSELECT(3 + (i > add_fd), i, a_rs, a_ws, a_es, a_tv); + if (i > add_fd) { printf("%s(%d, [%d %d %d], [%d %d %d %d], []" ", {tv_sec=%lld, tv_usec=%llu})" " = 4 (in [%d], out [1 2 %d]" ", left {tv_sec=%lld, tv_usec=%llu})\n", TEST_SYSCALL_STR, i, - fds[0], fds[1], PATH_TRACING_FD, + fds[0], fds[1], add_fd, 1, 2, fds[0], fds[1], (long long) tv_in.tv_sec, zero_extend_signed_to_ull(tv_in.tv_usec), - PATH_TRACING_FD, fds[1], + add_fd, fds[1], (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec)); } *l_rs = (1UL << fds[0]) | (1UL << fds[1]); *l_ws = (1UL << 1) | (1UL << 2) | - (1UL << fds[0]) | (1UL << fds[1]) | - (1UL << PATH_TRACING_FD); + (1UL << fds[0]) | (1UL << fds[1]) | (1UL << add_fd); tv_in.tv_sec = 0xc0de1; tv_in.tv_usec = 0xc0de2; memcpy(tv, &tv_in, sizeof(tv_in)); - XSELECT(3 + (i > PATH_TRACING_FD), i, a_rs, a_ws, a_es, a_tv); - if (i > PATH_TRACING_FD) { + XSELECT(3 + (i > add_fd), i, a_rs, a_ws, a_es, a_tv); + if (i > add_fd) { printf("%s(%d, [%d %d], [%d %d %d %d %d], []" ", {tv_sec=%lld, tv_usec=%llu})" " = 4 (out [1 2 %d %d]" ", left {tv_sec=%lld, tv_usec=%llu})\n", TEST_SYSCALL_STR, i, fds[0], fds[1], - 1, 2, fds[0], fds[1], PATH_TRACING_FD, + 1, 2, fds[0], fds[1], add_fd, (long long) tv_in.tv_sec, zero_extend_signed_to_ull(tv_in.tv_usec), - fds[1], PATH_TRACING_FD, + fds[1], add_fd, (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec)); } @@ -278,18 +310,18 @@ main(void) *l_rs = (1UL << fds[0]) | (1UL << fds[1]); *l_ws = (1UL << 1) | (1UL << 2) | (1UL << fds[0]) | (1UL << fds[1]); - *l_es = (1UL << PATH_TRACING_FD); + *l_es = (1UL << add_fd); tv_in.tv_sec = 0xc0de1; tv_in.tv_usec = 0xc0de2; memcpy(tv, &tv_in, sizeof(tv_in)); XSELECT(3, i, a_rs, a_ws, a_es, a_tv); - if (i > PATH_TRACING_FD) { + if (i > add_fd) { printf("%s(%d, [%d %d], [%d %d %d %d], [%d]" ", {tv_sec=%lld, tv_usec=%llu}) = 3 (out [1 2 %d]" ", left {tv_sec=%lld, tv_usec=%llu})\n", TEST_SYSCALL_STR, i, fds[0], fds[1], - 1, 2, fds[0], fds[1], PATH_TRACING_FD, + 1, 2, fds[0], fds[1], add_fd, (long long) tv_in.tv_sec, zero_extend_signed_to_ull(tv_in.tv_usec), fds[1], @@ -297,7 +329,7 @@ main(void) zero_extend_signed_to_ull(tv->tv_usec)); } -#endif /* PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ } /* @@ -307,7 +339,7 @@ main(void) static fd_set set[0x1000000 / sizeof(fd_set)]; FD_SET(fds[1], set); XSELECT(-1, -1U, 0, (uintptr_t) set, 0, 0); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(-1, NULL, %p, NULL, NULL) = %s\n", TEST_SYSCALL_STR, set, errstr); #endif @@ -329,22 +361,22 @@ main(void) tv->tv_sec = 0; tv->tv_usec = 10 + (i - FD_SETSIZE); XSELECT(0, i, a_big_rs, a_big_ws, 0, a_tv); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d], [], NULL, {tv_sec=0, tv_usec=%d})" " = 0 (Timeout)\n", TEST_SYSCALL_STR, i, fds[0], 10 + (i - FD_SETSIZE)); #else FD_SET(fds[0], big_rs); - FD_SET(PATH_TRACING_FD, big_rs); + FD_SET(add_fd, big_rs); tv->tv_sec = 0; tv->tv_usec = 10 + (i - FD_SETSIZE); XSELECT(1, i, a_big_rs, a_big_ws, 0, a_tv); printf("%s(%d, [%d %d], [], NULL, {tv_sec=0, tv_usec=%d})" " = 1 (in [%d], left {tv_sec=0, tv_usec=%llu})\n", - TEST_SYSCALL_STR, i, fds[0], PATH_TRACING_FD, - 10 + (i - FD_SETSIZE), PATH_TRACING_FD, + TEST_SYSCALL_STR, i, fds[0], add_fd, + 10 + (i - FD_SETSIZE), add_fd, zero_extend_signed_to_ull(tv->tv_usec)); -#endif /* PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ } /* @@ -356,35 +388,41 @@ main(void) tv->tv_usec = 123; XSELECT(0, INT_MAX, (uintptr_t) set, (uintptr_t) &set[1], (uintptr_t) &set[2], a_tv); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [], [], {tv_sec=0, tv_usec=123})" " = 0 (Timeout)\n", TEST_SYSCALL_STR, INT_MAX, fds[0], fds[1]); #else FD_SET(fds[0], set); FD_SET(fds[1], set); - FD_SET(PATH_TRACING_FD, set); + FD_SET(add_fd, set); tv->tv_sec = 0; tv->tv_usec = 123; XSELECT(1, INT_MAX, (uintptr_t) set, (uintptr_t) &set[1], (uintptr_t) &set[2], a_tv); printf("%s(%d, [%d %d %d], [], [], {tv_sec=0, tv_usec=123})" " = 1 (in [%d], left {tv_sec=0, tv_usec=%llu})\n", - TEST_SYSCALL_STR, INT_MAX, fds[0], fds[1], PATH_TRACING_FD, - PATH_TRACING_FD, zero_extend_signed_to_ull(tv->tv_usec)); -#endif /* PATH_TRACING_FD */ + TEST_SYSCALL_STR, INT_MAX, fds[0], fds[1], add_fd, + add_fd, zero_extend_signed_to_ull(tv->tv_usec)); +#endif /* !PATH_TRACING_FD && !TRACING_FD */ /* * Small sets, nfds exceeds FD_SETSIZE limit. * The kernel seems to be fine with it but strace cannot follow. */ *l_rs = (1UL << fds[0]) | (1UL << fds[1]) +#ifdef TRACING_FD + | (1UL << TRACING_FD) +#endif #ifdef PATH_TRACING_FD | (1UL << PATH_TRACING_FD) #endif ; *l_ws = (1UL << fds[0]); *l_es = (1UL << fds[0]) | (1UL << fds[1]) +#ifdef TRACING_FD + | (1UL << TRACING_FD) +#endif #ifdef PATH_TRACING_FD | (1UL << PATH_TRACING_FD) #endif @@ -393,12 +431,12 @@ main(void) tv->tv_usec = 123; rc = xselect(FD_SETSIZE + 1, a_rs, a_ws, a_es, a_tv); if (rc < 0) { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, %p, %p, %p, {tv_sec=0, tv_usec=123}) = %s\n", TEST_SYSCALL_STR, FD_SETSIZE + 1, rs, ws, es, errstr); #endif } else { -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, %p, %p, %p, {tv_sec=0, tv_usec=123})" " = 0 (Timeout)\n", TEST_SYSCALL_STR, FD_SETSIZE + 1, rs, ws, es); @@ -410,13 +448,18 @@ main(void) */ if (dup2(fds[1], smallset_size) != smallset_size) perror_msg_and_fail("dup2"); +#ifdef TRACING_FD + FD_SET(TRACING_FD, rs); + FD_SET(TRACING_FD, ws); + FD_SET(TRACING_FD, es); +#endif #ifdef PATH_TRACING_FD FD_SET(PATH_TRACING_FD, rs); FD_SET(PATH_TRACING_FD, ws); FD_SET(PATH_TRACING_FD, es); #endif XSELECT(-1, smallset_size + 1, a_rs, a_ws, a_es, 0); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, %p, %p, %p, NULL) = %s\n", TEST_SYSCALL_STR, smallset_size + 1, rs, ws, es, errstr); #endif @@ -432,22 +475,22 @@ main(void) FD_SET(fds[1], big_ws); FD_SET(smallset_size, big_ws); XSELECT(-1, smallset_size + 1, a_big_rs, a_big_ws, a_es, 0); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, [%d %d], [%d %d], %p, NULL) = %s\n", TEST_SYSCALL_STR, smallset_size + 1, fds[0], smallset_size, fds[1], smallset_size, es, errstr); -#endif /* !PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ XSELECT(-1, smallset_size + 1, a_es, a_big_ws, a_big_rs, 0); -#ifndef PATH_TRACING_FD +#if !defined(PATH_TRACING_FD) && !defined(TRACING_FD) printf("%s(%d, %p, [%d %d], [%d %d], NULL) = %s\n", TEST_SYSCALL_STR, smallset_size + 1, es, fds[1], smallset_size, fds[0], smallset_size, errstr); -#endif /* !PATH_TRACING_FD */ +#endif /* !PATH_TRACING_FD && !TRACING_FD */ puts("+++ exited with 0 +++"); return 0; |