1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2019 Paul Chaignon <paul.chaignon@gmail.com>
4 * Copyright (c) 2019-2023 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 /*
11 * open_memstream returns a FILE stream that allows writing to a
12 * dynamically growing buffer, that can be either copied to
13 * tcp->outf (syscall successful) or dropped (syscall failed)
14 */
15
16 #include "defs.h"
17
18 struct staged_output_data {
19 char *memfptr;
20 size_t memfloc;
21 FILE *real_outf; /* Backup for real outf while staging */
22 };
23
24 FILE *
25 strace_open_memstream(struct tcb *tcp)
26 {
27 FILE *fp = NULL;
28
29 #ifdef HAVE_OPEN_MEMSTREAM
30 tcp->staged_output_data = xmalloc(sizeof(*tcp->staged_output_data));
31 fp = open_memstream(&tcp->staged_output_data->memfptr,
32 &tcp->staged_output_data->memfloc);
33 if (!fp)
34 perror_msg_and_die("open_memstream");
35 /*
36 * Call to fflush required to update tcp->memfptr,
37 * see open_memstream man page.
38 */
39 fflush(fp);
40
41 /* Store the FILE pointer for later restoration. */
42 tcp->staged_output_data->real_outf = tcp->outf;
43 tcp->outf = fp;
44 #endif
45
46 return fp;
47 }
48
49 void
50 strace_close_memstream(struct tcb *tcp, bool publish)
51 {
52 #ifdef HAVE_OPEN_MEMSTREAM
53 if (!tcp->staged_output_data) {
54 debug_msg("memstream already closed");
55 return;
56 }
57
58 if (fclose(tcp->outf))
59 perror_msg("fclose(tcp->outf)");
60
61 tcp->outf = tcp->staged_output_data->real_outf;
62 if (tcp->staged_output_data->memfptr) {
63 if (publish)
64 fputs_unlocked(tcp->staged_output_data->memfptr,
65 tcp->outf);
66 else
67 debug_msg("syscall output dropped: %s",
68 tcp->staged_output_data->memfptr);
69
70 free(tcp->staged_output_data->memfptr);
71 tcp->staged_output_data->memfptr = NULL;
72 }
73 free(tcp->staged_output_data);
74 tcp->staged_output_data = NULL;
75 #endif
76 }