### Bug Summary

File: | builds/wireshark/wireshark/capture/capture_sync.c
Warning: | line 963, column 9 Potential leak of memory pointed to by 'argv'

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name capture_sync.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-08-05-100354-3660-1 -x c /builds/wireshark/wireshark/capture/capture_sync.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* capture_sync.c
2 | * Synchronisation between Wireshark capture parent and child instances
3 | *
4 | * Wireshark - Network traffic analyzer
5 | * By Gerald Combs <gerald@wireshark.org>
6 | * Copyright 1998 Gerald Combs
7 | *
8 | * SPDX-License-Identifier: GPL-2.0-or-later
9 | */
10 |
11 | #include "config.h"
12 | #define WS_LOG_DOMAIN"Capture" LOG_DOMAIN_CAPTURE"Capture"
13 |
14 | #include <wireshark.h>
15 |
16 | #ifdef HAVE_LIBPCAP1
17 |
18 | #include <glib.h>
19 | #include <stdio.h>
20 | #include <stdlib.h>
21 |
22 | #include <signal.h>
23 |
24 | #include <ws_exit_codes.h>
25 |
26 | #include <wsutil/strtoi.h>
27 | #include <wsutil/ws_assert.h>
28 | #include <wsutil/pint.h>
29 |
30 | #ifdef _WIN32
31 | #include <wsutil/unicode-utils.h>
32 | #include <wsutil/win32-utils.h>
33 | #include <wsutil/ws_pipe.h>
34 | #else
35 | #include <glib-unix1.h>
36 | #endif
37 |
38 | #include <app/application_flavor.h>
39 |
40 | #ifdef HAVE_SYS_WAIT_H1
41 | # include <sys/wait.h>
42 | #endif
43 |
44 | #include "capture/capture-pcap-util.h"
45 |
46 | #ifndef _WIN32
47 | /*
48 | * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
49 | * macros) on UNIX systems that don't have them.
50 | */
51 | #ifndef WIFEXITED
52 | # define WIFEXITED(status)(((status) & 0x7f) == 0) (((status) & 0177) == 0)
53 | #endif
54 | #ifndef WIFSTOPPED
55 | # define WIFSTOPPED(status)(((status) & 0xff) == 0x7f) (((status) & 0177) == 0177)
56 | #endif
57 | #ifndef WIFSIGNALED
58 | # define WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0 ) (!WIFSTOPPED(status)(((status) & 0xff) == 0x7f) && !WIFEXITED(status)(((status) & 0x7f) == 0))
59 | #endif
60 | #ifndef WEXITSTATUS
61 | # define WEXITSTATUS(status)(((status) & 0xff00) >> 8) ((status) >> 8)
62 | #endif
63 | #ifndef WTERMSIG
64 | # define WTERMSIG(status)((status) & 0x7f) ((status) & 0177)
65 | #endif
66 | #ifndef WCOREDUMP
67 | # define WCOREDUMP(status)((status) & 0x80) ((status) & 0200)
68 | #endif
69 | #ifndef WSTOPSIG
70 | # define WSTOPSIG(status)(((status) & 0xff00) >> 8) ((status) >> 8)
71 | #endif
72 | #endif /* _WIN32 */
73 |
74 | #include <epan/packet.h>
75 | #include <epan/prefs.h>
76 |
77 | #include "file.h"
78 |
79 | #include "ui/capture.h"
80 | #include <capture/capture_sync.h>
81 | #include <capture/sync_pipe.h>
82 |
83 | #ifdef _WIN32
84 | #include "capture/capture-wpcap.h"
85 | #endif
86 |
87 | #include "ui/ws_ui_util.h"
88 |
89 | #include <wsutil/filesystem.h>
90 | #include <wsutil/file_util.h>
91 | #include <wsutil/report_message.h>
92 | #include "extcap.h"
93 |
94 | #ifdef _WIN32
95 | #include <process.h> /* For spawning child process */
96 | #endif
97 |
98 | #include <wsutil/ws_pipe.h>
99 |
100 | #ifdef _WIN32
101 | static int create_dummy_signal_pipe(char **msg);
102 | static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
103 | static char *dummy_control_id;
104 | #else
105 | static const char *sync_pipe_signame(int);
106 | #endif
107 |
108 | /* We use this pipe buffer size for both the sync message pipe and the
109 | * data pipe. Ensure that it's large enough for the indicator and header
110 | * plus maximum message size.
111 | */
112 | #define PIPE_BUF_SIZE((512 * 1000)+4) (SP_MAX_MSG_LEN(512 * 1000)+4)
113 |
114 | static bool_Bool sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session);
115 | static int sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp);
116 | static void pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len);
117 | static ssize_t pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
118 | char **err_msg);
119 |
120 | static void (*fetch_dumpcap_pid)(ws_process_id);
121 |
122 | void
123 | capture_session_init(capture_session *cap_session, capture_file *cf,
124 | new_file_fn new_file, new_packets_fn new_packets,
125 | drops_fn drops, message_fn error,
126 | cfilter_error_fn cfilter_error,
127 | message_fn warning, closed_fn closed)
128 | {
129 | cap_session->cf = cf;
130 | cap_session->fork_child = WS_INVALID_PID-1; /* invalid process handle */
131 | cap_session->pipe_input_id = 0;
132 | #ifdef _WIN32
133 | cap_session->signal_pipe_write_fd = -1;
134 | #endif
135 | cap_session->state = CAPTURE_STOPPED;
136 | #ifndef _WIN32
137 | cap_session->owner = getuid();
138 | cap_session->group = getgid();
139 | #endif
140 | cap_session->count = 0;
141 | cap_session->count_pending = 0;
142 | cap_session->session_will_restart = false0;
143 |
144 | cap_session->new_file = new_file;
145 | cap_session->new_packets = new_packets;
146 | cap_session->drops = drops;
147 | cap_session->error = error;
148 | cap_session->cfilter_error = cfilter_error;
149 | cap_session->warning = warning;
150 | cap_session->closed = closed;
151 | cap_session->frame_cksum = NULL((void*)0);
152 | }
153 |
154 | void capture_process_finished(capture_session *cap_session)
155 | {
156 | capture_options *capture_opts = cap_session->capture_opts;
157 | interface_options *interface_opts;
158 | GString *message;
159 | unsigned i;
160 |
161 | if (!extcap_session_stop(cap_session)) {
162 | /* At least one extcap process did not fully finish yet, wait for it */
163 | return;
164 | }
165 |
166 | if (cap_session->fork_child != WS_INVALID_PID-1) {
167 | if (capture_opts->stop_after_extcaps) {
168 | /* User has requested capture stop and all extcaps are gone now */
169 | capture_opts->stop_after_extcaps = false0;
170 | sync_pipe_stop(cap_session);
171 | }
172 | /* Wait for child process to end, session is not closed yet */
173 | return;
174 | }
175 |
176 | /* Construct message and close session */
177 | message = g_string_new(capture_opts->closed_msg);
178 | for (i = 0; i < capture_opts->ifaces->len; i++) {
179 | interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i)(((interface_options*) (void *) (capture_opts->ifaces)-> data) [(i)]);
180 | if (interface_opts->if_type != IF_EXTCAP) {
181 | continue;
182 | }
183 |
184 | if ((interface_opts->extcap_stderr != NULL((void*)0)) &&
185 | (interface_opts->extcap_stderr->len > 0)) {
186 | if (message->len > 0) {
187 | g_string_append(message, "\n")(__builtin_constant_p ("\n") ? __extension__ ({ const char * const __val = ("\n"); g_string_append_len_inline (message, __val, ( __val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (message, "\n" , (gssize) -1));
188 | }
189 | g_string_append(message, "Error from extcap pipe: ")(__builtin_constant_p ("Error from extcap pipe: ") ? __extension__ ({ const char * const __val = ("Error from extcap pipe: "); g_string_append_len_inline (message, __val, (__val != ((void*)0)) ? (gssize) strlen ((( __val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (message, "Error from extcap pipe: ", (gssize) -1));
190 | g_string_append(message, interface_opts->extcap_stderr->str)(__builtin_constant_p (interface_opts->extcap_stderr->str ) ? __extension__ ({ const char * const __val = (interface_opts ->extcap_stderr->str); g_string_append_len_inline (message , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (message , interface_opts->extcap_stderr->str, (gssize) -1));
191 | }
192 | }
193 |
194 | cap_session->closed(cap_session, message->str);
195 | g_string_free(message, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (message), ((!(0)))) : g_string_free_and_steal (message)) : ( g_string_free) ((message), ((!(0)))));
196 | g_free(capture_opts->closed_msg)(__builtin_object_size ((capture_opts->closed_msg), 0) != ( (size_t) - 1)) ? g_free_sized (capture_opts->closed_msg, __builtin_object_size ((capture_opts->closed_msg), 0)) : (g_free) (capture_opts ->closed_msg);
197 | capture_opts->closed_msg = NULL((void*)0);
198 | capture_opts->stop_after_extcaps = false0;
199 | }
200 |
201 | /* Append an arg (realloc) to an argc/argv array */
202 | /* (add a string pointer to a NULL-terminated array of string pointers) */
203 | /* XXX: For glib >= 2.68 we could use a GStrvBuilder.
204 | */
205 | static char **
206 | sync_pipe_add_arg(char **args, int *argc, const char *arg)
207 | {
208 | /* Grow the array; "*argc" currently contains the number of string
209 | pointers, *not* counting the NULL pointer at the end, so we have
210 | to add 2 in order to get the new size of the array, including the
211 | new pointer and the terminating NULL pointer. */
212 | args = (char **)g_realloc( (void *) args, (*argc + 2) * sizeof (char *));
14 | ← | Memory is allocated | →
213 |
214 | /* Stuff the pointer into the penultimate element of the array, which
215 | is the one at the index specified by "*argc". */
216 | args[*argc] = g_strdup(arg)g_strdup_inline (arg);
217 | /* Now bump the count. */
218 | (*argc)++;
219 |
220 | /* We overwrite the NULL pointer; put it back right after the
221 | element we added. */
222 | args[*argc] = NULL((void*)0);
223 |
224 | return args;
225 | }
226 |
227 | /* Take a buffer from an SP_LOG_MSG from dumpcap and send it to our
228 | * current logger. Keep this in sync with the format used in
229 | * dumpcap_log_writer. (We might want to do more proper serialization
230 | * of more than just the log level.)
231 | */
232 | static void
233 | sync_pipe_handle_log_msg(const char *buffer) {
234 | const char *log_msg = NULL((void*)0);
235 | const char* end;
236 | uint32_t level = 0;
237 |
238 | if (ws_strtou32(buffer, &end, &level) && end[0] == ':') {
239 | log_msg = end + 1;
240 | }
241 | ws_log(LOG_DOMAIN_CAPCHILD"Capchild", level, "%s", log_msg);
242 | }
243 |
244 | /* Initialize an argument list and add dumpcap to it. */
245 | static char **
246 | init_pipe_args(int *argc) {
247 | char *exename;
248 | char **argv;
249 |
250 | /* Find the absolute path of the dumpcap executable. */
251 | exename = get_executable_path("dumpcap");
252 | if (exename == NULL((void*)0)) {
253 | return NULL((void*)0);
254 | }
255 |
256 | /* Allocate the string pointer array with enough space for the
257 | terminating NULL pointer. */
258 | *argc = 0;
259 | argv = (char **)g_malloc(sizeof (char *));
260 | *argv = NULL((void*)0);
261 |
262 | /* Make that the first argument in the argument list (argv[0]). */
263 | argv = sync_pipe_add_arg(argv, argc, exename);
264 |
265 | /* Tell dumpcap to log at the lowest level its domain (Capchild) is
266 | * set to log in the main program. (It might be in the special noisy
267 | * or debug filter, so we can't just check the overall level.)
268 | */
269 | for (enum ws_log_level level = LOG_LEVEL_NOISY; level != _LOG_LEVEL_LAST; level++) {
270 | if (ws_log_msg_is_active(LOG_DOMAIN_CAPCHILD"Capchild", level)) {
271 | argv = sync_pipe_add_arg(argv, argc, "--log-level");
272 | argv = sync_pipe_add_arg(argv, argc, ws_log_level_to_string(level));
273 | break;
274 | }
275 | }
276 |
277 | argv = sync_pipe_add_arg(argv, argc, "--application-flavor");
278 | argv = sync_pipe_add_arg(argv, argc, application_flavor_name_lower());
279 |
280 | /* sync_pipe_add_arg strdupes exename, so we should free our copy */
281 | g_free(exename)(__builtin_object_size ((exename), 0) != ((size_t) - 1)) ? g_free_sized (exename, __builtin_object_size ((exename), 0)) : (g_free) ( exename);
282 |
283 | return argv;
284 | }
285 |
286 | static gboolean
287 | pipe_io_cb(GIOChannel *pipe_io, GIOCondition condition _U___attribute__((unused)), void * user_data)
288 | {
289 | capture_session *cap_session = (capture_session *)user_data;
290 | if (!sync_pipe_input_cb(pipe_io, cap_session)) {
291 | cap_session->pipe_input_id = 0;
292 | return G_SOURCE_REMOVE(0);
293 | }
294 | return G_SOURCE_CONTINUE(!(0));
295 | }
296 |
297 | /*
298 | * Open two pipes to dumpcap with the supplied arguments, one for its
299 | * standard output and one for its standard error.
300 | *
301 | * On success, *msg is unchanged and 0 is returned; data_read_fd,
302 | * message_read_fd, and fork_child point to the standard output pipe's
303 | * file descriptor, the standard error pipe's file descriptor, and
304 | * the child's PID/handle, respectively.
305 | *
306 | * On failure, *msg points to an error message for the failure, and -1 is
307 | * returned, in which case *msg must be freed with g_free().
308 | */
309 | #define ARGV_NUMBER_LEN24 24
310 | static int
311 | #ifdef _WIN32
312 | sync_pipe_open_command(char **argv, int *data_read_fd,
313 | GIOChannel **message_read_io, int *signal_write_fd,
314 | ws_process_id *fork_child, GArray *ifaces,
315 | char **msg, void(*update_cb)(void))
316 | #else
317 | sync_pipe_open_command(char **argv, int *data_read_fd,
318 | GIOChannel **message_read_io, int *signal_write_fd _U___attribute__((unused)),
319 | ws_process_id *fork_child, GArray *ifaces _U___attribute__((unused)),
320 | char **msg, void(*update_cb)(void))
321 | #endif
322 | {
323 | enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
324 | int message_read_fd = -1;
325 | char sync_id[ARGV_NUMBER_LEN24];
326 | #ifdef _WIN32
327 | HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
328 | HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
329 | int signal_pipe_write_fd = -1;
330 | HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */
331 | char control_id[ARGV_NUMBER_LEN24];
332 | char *signal_pipe_name;
333 | size_t i_handles = 0;
334 | HANDLE *handles;
335 | GString *args = g_string_sized_new(200);
336 | char *quoted_arg;
337 | SECURITY_ATTRIBUTES sa;
338 | STARTUPINFO si;
339 | PROCESS_INFORMATION pi;
340 | int i;
341 | unsigned j;
342 | interface_options *interface_opts;
343 | #else
344 | int sync_pipe[2]; /* pipe used to send messages from child to parent */
345 | int data_pipe[2]; /* pipe used to send data from child to parent */
346 | #endif
347 | *fork_child = WS_INVALID_PID-1;
348 | if (data_read_fd != NULL((void*)0)) {
349 | *data_read_fd = -1;
350 | }
351 | *message_read_io = NULL((void*)0);
352 | ws_debug("sync_pipe_open_command")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 352, __func__, "sync_pipe_open_command"); } } while (0);
353 |
354 | if (!msg) {
355 | /* We can't return anything */
356 | g_strfreev(argv);
357 | #ifdef _WIN32
358 | g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free ) ((args), ((!(0)))));
359 | #endif
360 | return -1;
361 | }
362 |
363 | #ifdef _WIN32
364 | /* init SECURITY_ATTRIBUTES */
365 | sa.nLength = sizeof(SECURITY_ATTRIBUTES);
366 | sa.bInheritHandle = false0;
367 | sa.lpSecurityDescriptor = NULL((void*)0);
368 |
369 | /* Create a pipe for the child process to send us messages */
370 | /* (increase this value if you have trouble while fast capture file switches) */
371 | if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
372 | /* Couldn't create the message pipe between parent and child. */
373 | *msg = ws_strdup_printf("Couldn't create sync pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s" , win32strerror(GetLastError()))
374 | win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s" , win32strerror(GetLastError()));
375 | g_strfreev(argv);
376 | return -1;
377 | }
378 |
379 | /*
380 | * Associate a C run-time file handle with the Windows HANDLE for the
381 | * read side of the message pipe.
382 | *
383 | * (See http://www.flounder.com/handles.htm for information on various
384 | * types of file handle in C/C++ on Windows.)
385 | */
386 | message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
387 | if (message_read_fd == -1) {
388 | *msg = ws_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for message read pipe: %s" , g_strerror((*__errno_location ())));
389 | g_strfreev(argv);
390 | CloseHandle(sync_pipe[PIPE_READ]);
391 | CloseHandle(sync_pipe[PIPE_WRITE]);
392 | return -1;
393 | }
394 |
395 | if (data_read_fd != NULL((void*)0)) {
396 | /* Create a pipe for the child process to send us data */
397 | /* (increase this value if you have trouble while fast capture file switches) */
398 | if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
399 | /* Couldn't create the message pipe between parent and child. */
400 | *msg = ws_strdup_printf("Couldn't create data pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s" , win32strerror(GetLastError()))
401 | win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s" , win32strerror(GetLastError()));
402 | g_strfreev(argv);
403 | ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
404 | CloseHandle(sync_pipe[PIPE_WRITE]);
405 | return -1;
406 | }
407 |
408 | /*
409 | * Associate a C run-time file handle with the Windows HANDLE for the
410 | * read side of the data pipe.
411 | *
412 | * (See http://www.flounder.com/handles.htm for information on various
413 | * types of file handle in C/C++ on Windows.)
414 | */
415 | *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
416 | if (*data_read_fd == -1) {
417 | *msg = ws_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for data read pipe: %s" , g_strerror((*__errno_location ())));
418 | g_strfreev(argv);
419 | CloseHandle(data_pipe[PIPE_READ]);
420 | CloseHandle(data_pipe[PIPE_WRITE]);
421 | ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
422 | CloseHandle(sync_pipe[PIPE_WRITE]);
423 | return -1;
424 | }
425 | }
426 |
427 | if (signal_write_fd != NULL((void*)0)) {
428 | /* Create the signal pipe */
429 | snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
430 | signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, control_id );
431 | signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
432 | PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
433 | g_free(signal_pipe_name)(__builtin_object_size ((signal_pipe_name), 0) != ((size_t) - 1)) ? g_free_sized (signal_pipe_name, __builtin_object_size ( (signal_pipe_name), 0)) : (g_free) (signal_pipe_name);
434 |
435 | if (signal_pipe == INVALID_HANDLE_VALUE) {
436 | /* Couldn't create the signal pipe between parent and child. */
437 | *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s" , win32strerror(GetLastError()))
438 | win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s" , win32strerror(GetLastError()));
439 | g_strfreev(argv);
440 | ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
441 | CloseHandle(sync_pipe[PIPE_WRITE]);
442 | return -1;
443 | }
444 |
445 | /*
446 | * Associate a C run-time file handle with the Windows HANDLE for the
447 | * read side of the message pipe.
448 | *
449 | * (See http://www.flounder.com/handles.htm for information on various
450 | * types of file handle in C/C++ on Windows.)
451 | */
452 | signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
453 | if (signal_pipe_write_fd == -1) {
454 | /* Couldn't create the pipe between parent and child. */
455 | *msg = ws_strdup_printf("Couldn't get C file handle for sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for sync pipe: %s" , g_strerror((*__errno_location ())));
456 | g_strfreev(argv);
457 | ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
458 | CloseHandle(sync_pipe[PIPE_WRITE]);
459 | CloseHandle(signal_pipe);
460 | return -1;
461 | }
462 | }
463 |
464 | /* init STARTUPINFO & PROCESS_INFORMATION */
465 | memset(&si, 0, sizeof(si));
466 | si.cb = sizeof(si);
467 | memset(&pi, 0, sizeof(pi));
468 | #ifdef DEBUG_CHILD
469 | si.dwFlags = STARTF_USESHOWWINDOW;
470 | si.wShowWindow = SW_SHOW;
471 | #else
472 | si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
473 | si.wShowWindow = SW_HIDE; /* this hides the console window */
474 |
475 | if (data_read_fd == NULL((void*)0)) {
476 | si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
477 | si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
478 | } else {
479 | si.hStdInput = NULL((void*)0); /* handle for named pipe*/
480 | si.hStdOutput = data_pipe[PIPE_WRITE];
481 | }
482 | si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
483 |
484 | /* On Windows, "[a]n inherited handle refers to the same object in the child
485 | * process as it does in the parent process. It also has the same value."
486 | * https://learn.microsoft.com/en-us/windows/win32/procthread/inheritance
487 | * When converted to a file descriptor (via _open_osfhandle), the fd
488 | * value is not necessarily the same in the two processes, but the handle
489 | * value can be shared.
490 | * A HANDLE is a void* though "64-bit versions of Windows use 32-bit handles
491 | * for interoperability... only the lower 32 bits are significant, so it is
492 | * safe to truncate the handle... or sign-extend the handle"
493 | * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
494 | * So it should be fine to call PtrToLong instead of casting to intptr_t.
495 | * https://learn.microsoft.com/en-us/windows/win32/WinProg64/rules-for-using-pointers
496 | */
497 | int argc = g_strv_length(argv);
498 | argv = sync_pipe_add_arg(argv, &argc, "-Z");
499 | snprintf(sync_id, ARGV_NUMBER_LEN24, "%ld", PtrToLong(sync_pipe[PIPE_WRITE]));
500 | argv = sync_pipe_add_arg(argv, &argc, sync_id);
501 | #endif
502 |
503 | if (ifaces) {
504 | for (j = 0; j < ifaces->len; j++) {
505 | interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
506 | if (interface_opts->extcap_fifo != NULL((void*)0)) {
507 | i_handles++;
508 | }
509 | }
510 | }
511 | handles = g_new(HANDLE, 3 + i_handles)((HANDLE *) g_malloc_n ((3 + i_handles), sizeof (HANDLE)));
512 | i_handles = 0;
513 | if (si.hStdInput) {
514 | handles[i_handles++] = si.hStdInput;
515 | }
516 | if (si.hStdOutput && (si.hStdOutput != si.hStdInput)) {
517 | handles[i_handles++] = si.hStdOutput;
518 | }
519 | handles[i_handles++] = sync_pipe[PIPE_WRITE];
520 | if (ifaces) {
521 | for (j = 0; j < ifaces->len; j++) {
522 | interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
523 | if (interface_opts->extcap_fifo != NULL((void*)0)) {
524 | handles[i_handles++] = interface_opts->extcap_pipe_h;
525 | }
526 | }
527 | }
528 |
529 | /* convert args array into a single string */
530 | /* XXX - could change sync_pipe_add_arg() instead */
531 | /* there is a drawback here: the length is internally limited to 1024 bytes */
532 | for(i=0; argv[i] != 0; i++) {
533 | if(i != 0) g_string_append_c(args, ' ')g_string_append_c_inline (args, ' '); /* don't prepend a space before the path!!! */
534 | quoted_arg = protect_arg(argv[i]);
535 | g_string_append(args, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char * const __val = (quoted_arg); g_string_append_len_inline (args , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (args , quoted_arg, (gssize) -1));
536 | g_free(quoted_arg)(__builtin_object_size ((quoted_arg), 0) != ((size_t) - 1)) ? g_free_sized (quoted_arg, __builtin_object_size ((quoted_arg ), 0)) : (g_free) (quoted_arg);
537 | }
538 |
539 | /* call dumpcap */
540 | if(!win32_create_process(argv[0], args->str, NULL((void*)0), NULL((void*)0), i_handles, handles,
541 | CREATE_NEW_CONSOLE, NULL((void*)0), NULL((void*)0), &si, &pi)) {
542 | *msg = ws_strdup_printf("Couldn't run %s in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s" , args->str, win32strerror(GetLastError()))
543 | args->str, win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s" , args->str, win32strerror(GetLastError()));
544 | if (data_read_fd) {
545 | ws_closeclose(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
546 | CloseHandle(data_pipe[PIPE_WRITE]);
547 | } else {
548 | ws_closeclose(signal_pipe_write_fd);
549 | }
550 | ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
551 | CloseHandle(sync_pipe[PIPE_WRITE]);
552 | g_strfreev(argv);
553 | g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free ) ((args), ((!(0)))));
554 | g_free(handles)(__builtin_object_size ((handles), 0) != ((size_t) - 1)) ? g_free_sized (handles, __builtin_object_size ((handles), 0)) : (g_free) ( handles);
555 | return -1;
556 | }
557 | *fork_child = pi.hProcess;
558 | /* We may need to store this and close it later */
559 | CloseHandle(pi.hThread);
560 | g_strfreev(argv);
561 | g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free ) ((args), ((!(0)))));
562 | g_free(handles)(__builtin_object_size ((handles), 0) != ((size_t) - 1)) ? g_free_sized (handles, __builtin_object_size ((handles), 0)) : (g_free) ( handles);
563 |
564 | if (signal_write_fd != NULL((void*)0)) {
565 | *signal_write_fd = signal_pipe_write_fd;
566 | }
567 | #else /* _WIN32 */
568 | /* Create a pipe for the child process to send us messages */
569 | if (pipe(sync_pipe) < 0) {
570 | /* Couldn't create the message pipe between parent and child. */
571 | *msg = ws_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s" , g_strerror((*__errno_location ())));
572 | g_strfreev(argv);
573 | return -1;
574 | }
575 |
576 | if (data_read_fd != NULL((void*)0)) {
577 | /* Create a pipe for the child process to send us data */
578 | if (pipe(data_pipe) < 0) {
579 | /* Couldn't create the data pipe between parent and child. */
580 | *msg = ws_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s" , g_strerror((*__errno_location ())));
581 | g_strfreev(argv);
582 | ws_closeclose(sync_pipe[PIPE_READ]);
583 | ws_closeclose(sync_pipe[PIPE_WRITE]);
584 | return -1;
585 | }
586 | }
587 |
588 | if ((*fork_child = fork()) == 0) {
589 | /*
590 | * Child process - run dumpcap with the right arguments to make
591 | * it just capture with the specified capture parameters
592 | */
593 | if (data_read_fd != NULL((void*)0)) {
594 | dup2(data_pipe[PIPE_WRITE], 1);
595 | ws_closeclose(data_pipe[PIPE_READ]);
596 | ws_closeclose(data_pipe[PIPE_WRITE]);
597 | }
598 | ws_closeclose(sync_pipe[PIPE_READ]);
599 | /* dumpcap should be running in capture child mode (hidden feature) */
600 | #ifndef DEBUG_CHILD
601 | int argc = g_strv_length(argv);
602 | argv = sync_pipe_add_arg(argv, &argc, "-Z");
603 | snprintf(sync_id, ARGV_NUMBER_LEN24, "%d", sync_pipe[PIPE_WRITE]);
604 | argv = sync_pipe_add_arg(argv, &argc, sync_id);
605 | #endif
606 | execv(argv[0], argv);
607 | sync_pipe_write_int_msg(sync_pipe[PIPE_WRITE], SP_EXEC_FAILED'X', errno(*__errno_location ()));
608 |
609 | /* Exit with "_exit()", so that we don't close the connection
610 | to the X server (and cause stuff buffered up by our parent but
611 | not yet sent to be sent, as that stuff should only be sent by
612 | our parent). We've sent an error message to the parent, so
613 | we exit with an exit status of 1 (any exit status other than
614 | 0 or 1 will cause an additional message to report that exit
615 | status, over and above the error message we sent to the parent). */
616 | _exit(1);
617 | }
618 |
619 | g_strfreev(argv);
620 |
621 | if (fetch_dumpcap_pid && *fork_child > 0)
622 | fetch_dumpcap_pid(*fork_child);
623 |
624 | if (data_read_fd != NULL((void*)0)) {
625 | *data_read_fd = data_pipe[PIPE_READ];
626 | }
627 | message_read_fd = sync_pipe[PIPE_READ];
628 |
629 | #endif
630 |
631 | /* Parent process - read messages from the child process over the
632 | sync pipe. */
633 |
634 | /* Close the write sides of the pipes, so that only the child has them
635 | open, and thus they completely close, and thus return to us
636 | an EOF indication, if the child closes them (either deliberately
637 | or by exiting abnormally). */
638 | #ifdef _WIN32
639 | if (data_read_fd != NULL((void*)0)) {
640 | CloseHandle(data_pipe[PIPE_WRITE]);
641 | }
642 | CloseHandle(sync_pipe[PIPE_WRITE]);
643 | #else
644 | if (data_read_fd != NULL((void*)0)) {
645 | ws_closeclose(data_pipe[PIPE_WRITE]);
646 | }
647 | ws_closeclose(sync_pipe[PIPE_WRITE]);
648 | #endif
649 |
650 | if (*fork_child == WS_INVALID_PID-1) {
651 | /* We couldn't even create the child process. */
652 | *msg = ws_strdup_printf("Couldn't create child process: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create child process: %s" , g_strerror((*__errno_location ())));
653 | if (data_read_fd != NULL((void*)0)) {
654 | ws_closeclose(*data_read_fd);
655 | }
656 | #ifdef _WIN32
657 | if (signal_write_fd != NULL((void*)0)) {
658 | ws_closeclose(signal_pipe_write_fd);
659 | }
660 | #endif
661 | ws_closeclose(message_read_fd);
662 | return -1;
663 | }
664 |
665 | #ifdef _WIN32
666 | *message_read_io = g_io_channel_win32_new_fd(message_read_fd);
667 | #else
668 | *message_read_io = g_io_channel_unix_new(message_read_fd);
669 | #endif
670 | g_io_channel_set_encoding(*message_read_io, NULL((void*)0), NULL((void*)0));
671 | g_io_channel_set_buffered(*message_read_io, false0);
672 | g_io_channel_set_close_on_unref(*message_read_io, true1);
673 |
674 | /* we might wait for a moment till child is ready, so update screen now */
675 | if (update_cb) update_cb();
676 | return 0;
677 | }
678 |
679 | /* a new capture run: start a new dumpcap task and hand over parameters through command line */
680 | bool_Bool
681 | sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
682 | capture_session *cap_session, info_data_t* cap_data,
683 | void (*update_cb)(void))
684 | {
685 | #ifdef _WIN32
686 | char control_id[ARGV_NUMBER_LEN24];
687 | #endif
688 | GIOChannel *sync_pipe_read_io;
689 | int argc;
690 | char **argv;
691 | int i;
692 | unsigned j;
693 | interface_options *interface_opts;
694 |
695 | if (capture_opts->ifaces->len > 1)
1 | Assuming field 'len' is <= 1 | →
2 | ← | Taking false branch | →
696 | capture_opts->use_pcapng = true1;
697 | ws_debug("sync_pipe_start")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 697, __func__, "sync_pipe_start"); } } while (0);
3 | ← | Taking true branch | →
4 | ← | Loop condition is false. Exiting loop | →
698 | capture_opts_log(LOG_DOMAIN_CAPTURE"Capture", LOG_LEVEL_DEBUG, capture_opts);
699 |
700 | cap_session->fork_child = WS_INVALID_PID-1;
701 | cap_session->capture_opts = capture_opts;
702 |
703 | if (!extcap_init_interfaces(cap_session)) {
5 | ← | Assuming the condition is false | →
6 | ← | Taking false branch | →
704 | report_failure("Unable to init extcaps. (tmp fifo already exists?)");
705 | return false0;
706 | }
707 |
708 | argv = init_pipe_args(&argc);
709 | if (!argv) {
7 | ← | Assuming 'argv' is non-null | →
8 | ← | Taking false branch | →
710 | /* We don't know where to find dumpcap. */
711 | report_failure("We don't know where to find dumpcap.");
712 | return false0;
713 | }
714 |
715 | if (capture_opts->ifaces->len > 1)
9 | ← | Assuming field 'len' is <= 1 | →
10 | ← | Taking false branch | →
716 | argv = sync_pipe_add_arg(argv, &argc, "-t");
717 |
718 | argv = sync_pipe_add_arg(argv, &argc, "-F");
719 | if (capture_opts->use_pcapng)
11 | ← | Assuming field 'use_pcapng' is false | →
12 | ← | Taking false branch | →
720 | argv = sync_pipe_add_arg(argv, &argc, "pcapng");
721 | else
722 | argv = sync_pipe_add_arg(argv, &argc, "pcap");
13 | ← | Calling 'sync_pipe_add_arg' | →
15 | ← | Returned allocated memory | →
723 |
724 | if (capture_comments != NULL((void*)0)) {
16 | ← | Assuming 'capture_comments' is equal to NULL | →
17 | ← | Taking false branch | →
725 | for (j = 0; j < capture_comments->len; j++) {
726 | argv = sync_pipe_add_arg(argv, &argc, "--capture-comment");
727 | argv = sync_pipe_add_arg(argv, &argc, (char*)g_ptr_array_index(capture_comments, j)((capture_comments)->pdata)[j]);
728 | }
729 | }
730 |
731 | if (capture_opts->temp_dir) {
18 | ← | Assuming field 'temp_dir' is null | →
19 | ← | Taking false branch | →
732 | argv = sync_pipe_add_arg(argv, &argc, "--temp-dir");
733 | argv = sync_pipe_add_arg(argv, &argc, capture_opts->temp_dir);
734 | }
735 |
736 | if (capture_opts->multi_files_on) {
20 | ← | Assuming field 'multi_files_on' is false | →
21 | ← | Taking false branch | →
737 | if (capture_opts->has_autostop_filesize) {
738 | char sfilesize[ARGV_NUMBER_LEN24];
739 | argv = sync_pipe_add_arg(argv, &argc, "-b");
740 | snprintf(sfilesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
741 | argv = sync_pipe_add_arg(argv, &argc, sfilesize);
742 | }
743 |
744 | if (capture_opts->has_file_duration) {
745 | char sfile_duration[ARGV_NUMBER_LEN24];
746 | argv = sync_pipe_add_arg(argv, &argc, "-b");
747 | snprintf(sfile_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->file_duration);
748 | argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
749 | }
750 |
751 | if (capture_opts->has_file_interval) {
752 | char sfile_interval[ARGV_NUMBER_LEN24];
753 | argv = sync_pipe_add_arg(argv, &argc, "-b");
754 | snprintf(sfile_interval, ARGV_NUMBER_LEN24, "interval:%d",capture_opts->file_interval);
755 | argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
756 | }
757 |
758 | if (capture_opts->has_file_packets) {
759 | char sfile_packets[ARGV_NUMBER_LEN24];
760 | argv = sync_pipe_add_arg(argv, &argc, "-b");
761 | snprintf(sfile_packets, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->file_packets);
762 | argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
763 | }
764 |
765 | if (capture_opts->has_ring_num_files) {
766 | char sring_num_files[ARGV_NUMBER_LEN24];
767 | argv = sync_pipe_add_arg(argv, &argc, "-b");
768 | snprintf(sring_num_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->ring_num_files);
769 | argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
770 | }
771 |
772 | if (capture_opts->print_file_names) {
773 | char *print_name = g_strdup_printf("printname:%s", capture_opts->print_name_to);
774 | argv = sync_pipe_add_arg(argv, &argc, "-b");
775 | argv = sync_pipe_add_arg(argv, &argc, print_name);
776 | g_free(print_name)(__builtin_object_size ((print_name), 0) != ((size_t) - 1)) ? g_free_sized (print_name, __builtin_object_size ((print_name ), 0)) : (g_free) (print_name);
777 | }
778 |
779 | if (capture_opts->has_nametimenum) {
780 | char nametimenum[ARGV_NUMBER_LEN24];
781 | argv = sync_pipe_add_arg(argv, &argc, "-b");
782 | snprintf(nametimenum, ARGV_NUMBER_LEN24, "nametimenum:2");
783 | argv = sync_pipe_add_arg(argv, &argc, nametimenum);
784 | }
785 |
786 | if (capture_opts->has_autostop_files) {
787 | char sautostop_files[ARGV_NUMBER_LEN24];
788 | argv = sync_pipe_add_arg(argv, &argc, "-a");
789 | snprintf(sautostop_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->autostop_files);
790 | argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
791 | }
792 | } else {
793 | if (capture_opts->has_autostop_filesize) {
22 | ← | Assuming field 'has_autostop_filesize' is false | →
23 | ← | Taking false branch | →
794 | char sautostop_filesize[ARGV_NUMBER_LEN24];
795 | argv = sync_pipe_add_arg(argv, &argc, "-a");
796 | snprintf(sautostop_filesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
797 | argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
798 | }
799 | }
800 |
801 | if (capture_opts->has_autostop_packets) {
24 | ← | Assuming field 'has_autostop_packets' is false | →
25 | ← | Taking false branch | →
802 | char scount[ARGV_NUMBER_LEN24];
803 | argv = sync_pipe_add_arg(argv, &argc, "-c");
804 | snprintf(scount, ARGV_NUMBER_LEN24, "%d",capture_opts->autostop_packets);
805 | argv = sync_pipe_add_arg(argv, &argc, scount);
806 | }
807 |
808 | if (capture_opts->has_autostop_duration) {
26 | ← | Assuming field 'has_autostop_duration' is false | →
27 | ← | Taking false branch | →
809 | char sautostop_duration[ARGV_NUMBER_LEN24];
810 | argv = sync_pipe_add_arg(argv, &argc, "-a");
811 | snprintf(sautostop_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->autostop_duration);
812 | argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
813 | }
814 |
815 | if (capture_opts->has_autostop_written_packets) {
28 | ← | Assuming field 'has_autostop_written_packets' is false | →
29 | ← | Taking false branch | →
816 | char scount[ARGV_NUMBER_LEN24];
817 | argv = sync_pipe_add_arg(argv, &argc, "-a");
818 | snprintf(scount, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->autostop_written_packets);
819 | argv = sync_pipe_add_arg(argv, &argc, scount);
820 | }
821 |
822 | if (capture_opts->group_read_access) {
30 | ← | Assuming field 'group_read_access' is false | →
31 | ← | Taking false branch | →
823 | argv = sync_pipe_add_arg(argv, &argc, "-g");
824 | }
825 |
826 | if (capture_opts->update_interval != DEFAULT_UPDATE_INTERVAL100) {
32 | ← | Assuming field 'update_interval' is equal to DEFAULT_UPDATE_INTERVAL | →
33 | ← | Taking false branch | →
827 | char scount[ARGV_NUMBER_LEN24];
828 | argv = sync_pipe_add_arg(argv, &argc, "--update-interval");
829 | snprintf(scount, ARGV_NUMBER_LEN24, "%d", capture_opts->update_interval);
830 | argv = sync_pipe_add_arg(argv, &argc, scount);
831 | }
832 |
833 | for (j = 0; j < capture_opts->ifaces->len; j++) {
34 | ← | Assuming 'j' is >= field 'len' | →
35 | ← | Loop condition is false. Execution continues on line 945 | →
834 | interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j)(((interface_options*) (void *) (capture_opts->ifaces)-> data) [(j)]);
835 |
836 | argv = sync_pipe_add_arg(argv, &argc, "-i");
837 | if (interface_opts->extcap_fifo != NULL((void*)0))
838 | {
839 | #ifdef _WIN32
840 | char *pipe = ws_strdup_printf("%s%" PRIuMAX, EXTCAP_PIPE_PREFIX, (uintmax_t)interface_opts->extcap_pipe_h)wmem_strdup_printf(((void*)0), "%s%" "l" "u", "wireshark_extcap" , (uintmax_t)interface_opts->extcap_pipe_h);
841 | argv = sync_pipe_add_arg(argv, &argc, pipe);
842 | g_free(pipe)(__builtin_object_size ((pipe), 0) != ((size_t) - 1)) ? g_free_sized (pipe, __builtin_object_size ((pipe), 0)) : (g_free) (pipe);
843 | #else
844 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->extcap_fifo);
845 | #endif
846 | /* Add a name for the interface, to put into an IDB. */
847 | argv = sync_pipe_add_arg(argv, &argc, "--ifname");
848 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
849 | }
850 | else
851 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
852 |
853 | if (interface_opts->descr != NULL((void*)0))
854 | {
855 | /* Add a description for the interface to put into an IDB and
856 | * use for the temporary filename. */
857 | argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
858 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
859 | }
860 |
861 | if (interface_opts->cfilter != NULL((void*)0) && strlen(interface_opts->cfilter) != 0) {
862 | argv = sync_pipe_add_arg(argv, &argc, "-f");
863 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
864 | }
865 | if (!interface_opts->optimize) {
866 | argv = sync_pipe_add_arg(argv, &argc, "--no-optimize");
867 | }
868 | if (interface_opts->has_snaplen) {
869 | char ssnap[ARGV_NUMBER_LEN24];
870 | argv = sync_pipe_add_arg(argv, &argc, "-s");
871 | snprintf(ssnap, ARGV_NUMBER_LEN24, "%d", interface_opts->snaplen);
872 | argv = sync_pipe_add_arg(argv, &argc, ssnap);
873 | }
874 |
875 | if (interface_opts->linktype != -1) {
876 | const char *linktype = linktype_val_to_name(interface_opts->linktype);
877 | if ( linktype != NULL((void*)0) )
878 | {
879 | argv = sync_pipe_add_arg(argv, &argc, "-y");
880 | argv = sync_pipe_add_arg(argv, &argc, linktype);
881 | }
882 | }
883 |
884 | if (!interface_opts->promisc_mode) {
885 | argv = sync_pipe_add_arg(argv, &argc, "-p");
886 | }
887 |
888 | if (interface_opts->buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE2) {
889 | char buffer_size[ARGV_NUMBER_LEN24];
890 | argv = sync_pipe_add_arg(argv, &argc, "-B");
891 | if(interface_opts->buffer_size == 0x00)
892 | interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE2;
893 | snprintf(buffer_size, ARGV_NUMBER_LEN24, "%d", interface_opts->buffer_size);
894 | argv = sync_pipe_add_arg(argv, &argc, buffer_size);
895 | }
896 |
897 | if (interface_opts->monitor_mode) {
898 | argv = sync_pipe_add_arg(argv, &argc, "-I");
899 | }
900 |
901 | #ifdef HAVE_PCAP_REMOTE
902 | if (interface_opts->datatx_udp)
903 | argv = sync_pipe_add_arg(argv, &argc, "-u");
904 |
905 | if (!interface_opts->nocap_rpcap)
906 | argv = sync_pipe_add_arg(argv, &argc, "-r");
907 |
908 | if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
909 | char sauth[256];
910 | argv = sync_pipe_add_arg(argv, &argc, "-A");
911 | snprintf(sauth, sizeof(sauth), "%s:%s",
912 | interface_opts->auth_username,
913 | interface_opts->auth_password);
914 | argv = sync_pipe_add_arg(argv, &argc, sauth);
915 | }
916 | #endif
917 |
918 | #ifdef HAVE_PCAP_SETSAMPLING
919 | if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
920 | char ssampling[ARGV_NUMBER_LEN24];
921 | argv = sync_pipe_add_arg(argv, &argc, "-m");
922 | snprintf(ssampling, ARGV_NUMBER_LEN24, "%s:%d",
923 | interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :
924 | interface_opts->sampling_method == CAPTURE_SAMP_BY_TIMER ? "timer" :
925 | "undef",
926 | interface_opts->sampling_param);
927 | argv = sync_pipe_add_arg(argv, &argc, ssampling);
928 | }
929 | #endif
930 | if (interface_opts->timestamp_type) {
931 | argv = sync_pipe_add_arg(argv, &argc, "--time-stamp-type");
932 | argv = sync_pipe_add_arg(argv, &argc, interface_opts->timestamp_type);
933 | }
934 | }
935 |
936 | #ifndef DEBUG_CHILD
937 | #ifdef _WIN32
938 | /* pass process id to dumpcap for named signal pipe */
939 | argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
940 | snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
941 | argv = sync_pipe_add_arg(argv, &argc, control_id);
942 | #endif
943 | #endif
944 |
945 | if (capture_opts->save_file) {
36 | ← | Assuming field 'save_file' is null | →
37 | ← | Taking false branch | →
946 | argv = sync_pipe_add_arg(argv, &argc, "-w");
947 | argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
948 | }
949 | for (i = 0; i < argc; i++) {
38 | ← | Assuming 'i' is >= 'argc' | →
39 | ← | Loop condition is false. Execution continues on line 952 | →
950 | ws_debug("argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 950, __func__, "argv[%d]: %s", i, argv[i]); } } while (0);
951 | }
952 | if (capture_opts->compress_type) {
40 | ← | Assuming field 'compress_type' is null | →
41 | ← | Taking false branch | →
953 | argv = sync_pipe_add_arg(argv, &argc, "--compress-type");
954 | argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
955 | }
956 |
957 | int ret;
958 | char* msg;
959 | #ifdef _WIN32
960 | ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, &cap_session->signal_pipe_write_fd,
961 | &cap_session->fork_child, capture_opts->ifaces, &msg, update_cb);
962 | #else
963 | ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, NULL((void*)0),
42 | ← | Potential leak of memory pointed to by 'argv'
964 | &cap_session->fork_child, NULL((void*)0), &msg, update_cb);
965 | #endif
966 |
967 | if (ret == -1) {
968 | report_failure("%s", msg);
969 | g_free(msg)(__builtin_object_size ((msg), 0) != ((size_t) - 1)) ? g_free_sized (msg, __builtin_object_size ((msg), 0)) : (g_free) (msg);
970 | return false0;
971 | }
972 |
973 | /* Parent process - read messages from the child process over the
974 | sync pipe. */
975 |
976 | cap_session->fork_child_status = 0;
977 | cap_session->cap_data_info = cap_data;
978 |
979 | /* We were able to set up to read the capture file;
980 | arrange that our callback be called whenever it's possible
981 | to read from the sync pipe, so that it's called when
982 | the child process wants to tell us something. */
983 |
984 | /* we have a running capture, now wait for the real capture filename */
985 | if (cap_session->pipe_input_id) {
986 | g_source_remove(cap_session->pipe_input_id);
987 | cap_session->pipe_input_id = 0;
988 | }
989 | cap_session->pipe_input_id = g_io_add_watch(sync_pipe_read_io, G_IO_IN | G_IO_HUP, pipe_io_cb, cap_session);
990 | /* Pipe will be closed when watch is removed */
991 | g_io_channel_unref(sync_pipe_read_io);
992 |
993 | return true1;
994 | }
995 |
996 | /*
997 | * Close the pipes we're using to read from dumpcap, and wait for it
998 | * to exit. On success, *msgp is unchanged, and the exit status of
999 | * dumpcap is returned. On failure (which includes "dumpcap exited
1000 | * due to being killed by a signal or an exception"), *msgp points
1001 | * to an error message for the failure, and -1 is returned. In the
1002 | * latter case, *msgp must be freed with g_free().
1003 | */
1004 | static int
1005 | sync_pipe_close_command(int *data_read_fd, GIOChannel *message_read_io,
1006 | ws_process_id *fork_child, char **msgp)
1007 | {
1008 | ws_closeclose(*data_read_fd);
1009 | if (message_read_io != NULL((void*)0))
1010 | g_io_channel_unref(message_read_io);
1011 |
1012 | #ifdef _WIN32
1013 | /* XXX - Should we signal the child somehow? */
1014 | sync_pipe_kill(*fork_child);
1015 | #endif
1016 |
1017 | return sync_pipe_wait_for_child(*fork_child, msgp);
1018 | }
1019 |
1020 | /*
1021 | * Run dumpcap with the supplied arguments.
1022 | *
1023 | * On success, *data points to a buffer containing the dumpcap output,
1024 | * *primary_msg and *secondary_message are NULL, and 0 is returned; *data
1025 | * must be freed with g_free().
1026 | *
1027 | * On failure, *data is NULL, *primary_msg points to an error message,
1028 | * *secondary_msg either points to an additional error message or is
1029 | * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1030 | * must be freed with g_free().
1031 | */
1032 | static int
1033 | sync_pipe_run_command_actual(char **argv, char **data, char **primary_msg,
1034 | char **secondary_msg, void(*update_cb)(void))
1035 | {
1036 | char *msg;
1037 | int data_pipe_read_fd, ret;
1038 | GIOChannel *sync_pipe_read_io;
1039 | ws_process_id fork_child;
1040 | char *wait_msg;
1041 | char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1042 | ssize_t nread;
1043 | char indicator;
1044 | int32_t exec_errno = 0;
1045 | unsigned primary_msg_len;
1046 | const char *primary_msg_text;
1047 | unsigned secondary_msg_len;
1048 | const char *secondary_msg_text;
1049 | char *combined_msg;
1050 | GString *data_buf = NULL((void*)0);
1051 | ssize_t count;
1052 |
1053 | if (buffer == NULL((void*)0)) {
1054 | /* g_malloc is supposed to terminate the program if this fails, but,
1055 | * at least on a RELEASE build, some versions of gcc don't think that
1056 | * happens.
1057 | */
1058 | *primary_msg = ws_strdup_printf("Couldn't allocate memory for dumpcap output buffer: %s",wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s" , g_strerror((*__errno_location ())))
1059 | g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s" , g_strerror((*__errno_location ())));
1060 | *secondary_msg = NULL((void*)0);
1061 | *data = NULL((void*)0);
1062 | return -1;
1063 | }
1064 |
1065 | ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_io, NULL((void*)0),
1066 | &fork_child, NULL((void*)0), &msg, update_cb);
1067 | if (ret == -1) {
1068 | *primary_msg = msg;
1069 | *secondary_msg = NULL((void*)0);
1070 | *data = NULL((void*)0);
1071 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1072 | return -1;
1073 | }
1074 |
1075 | /*
1076 | * We were able to set up to read dumpcap's output. Do so.
1077 | *
1078 | * First, wait for an SP_ERROR_MSG message or an SP_SUCCESS message.
1079 | */
1080 | do {
1081 | nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1082 | buffer, primary_msg);
1083 | if(nread <= 0) {
1084 | /* We got a read error from the sync pipe, or we got no data at
1085 | all from the sync pipe, so we're not going to be getting any
1086 | data or error message from the child process. Pick up its
1087 | exit status, and complain.
1088 |
1089 | We don't have to worry about killing the child, if the sync pipe
1090 | returned an error. Usually this error is caused as the child killed
1091 | itself while going down. Even in the rare cases that this isn't the
1092 | case, the child will get an error when writing to the broken pipe
1093 | the next time, cleaning itself up then. */
1094 | g_io_channel_unref(sync_pipe_read_io);
1095 | ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
1096 | if(nread == 0) {
1097 | /* We got an EOF from the sync pipe. That means that it exited
1098 | before giving us any data to read. If ret is -1, we report
1099 | that as a bad exit (e.g., exiting due to a signal); otherwise,
1100 | we report it as a premature exit. */
1101 | if (ret == -1)
1102 | *primary_msg = wait_msg;
1103 | else
1104 | *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely" );
1105 | } else {
1106 | /* We got an error from the sync pipe. If ret is -1, report
1107 | both the sync pipe I/O error and the wait error. */
1108 | if (ret == -1) {
1109 | combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *primary_msg, wait_msg );
1110 | g_free(*primary_msg)(__builtin_object_size ((*primary_msg), 0) != ((size_t) - 1)) ? g_free_sized (*primary_msg, __builtin_object_size ((*primary_msg ), 0)) : (g_free) (*primary_msg);
1111 | g_free(wait_msg)(__builtin_object_size ((wait_msg), 0) != ((size_t) - 1)) ? g_free_sized (wait_msg, __builtin_object_size ((wait_msg), 0)) : (g_free) (wait_msg);
1112 | *primary_msg = combined_msg;
1113 | }
1114 | }
1115 | *secondary_msg = NULL((void*)0);
1116 | *data = NULL((void*)0);
1117 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1118 |
1119 | return -1;
1120 | }
1121 |
1122 | /* we got a valid message block from the child, process it */
1123 | switch(indicator) {
1124 |
1125 | case SP_EXEC_FAILED'X':
1126 | /*
1127 | * Exec of dumpcap failed. Get the errno for the failure.
1128 | */
1129 | if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1130 | ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 1130, __func__, "Invalid errno: %s", buffer); } } while (0);
1131 | }
1132 |
1133 | /*
1134 | * Pick up the child status.
1135 | */
1136 | ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1137 | &fork_child, &msg);
1138 | if (ret == -1) {
1139 | /*
1140 | * Child process failed unexpectedly, or wait failed; msg is the
1141 | * error message.
1142 | */
1143 | *primary_msg = msg;
1144 | *secondary_msg = NULL((void*)0);
1145 | } else {
1146 | /*
1147 | * Child process failed, but returned the expected exit status.
1148 | * Return the messages it gave us, and indicate failure.
1149 | */
1150 | *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno))
1151 | g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno));
1152 | *secondary_msg = NULL((void*)0);
1153 | ret = -1;
1154 | }
1155 | *data = NULL((void*)0);
1156 | break;
1157 |
1158 | case SP_ERROR_MSG'E':
1159 | /*
1160 | * Error from dumpcap; there will be a primary message and a
1161 | * secondary message.
1162 | */
1163 |
1164 | /* convert primary message */
1165 | pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1166 | primary_msg_text = buffer+4;
1167 | /* convert secondary message */
1168 | pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1169 | &secondary_msg_len);
1170 | secondary_msg_text = primary_msg_text + primary_msg_len + 4;
1171 | /* the capture child will close the sync_pipe, nothing to do */
1172 |
1173 | /*
1174 | * Pick up the child status.
1175 | */
1176 | ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1177 | &fork_child, &msg);
1178 | if (ret == -1) {
1179 | /*
1180 | * Child process failed unexpectedly, or wait failed; msg is the
1181 | * error message.
1182 | */
1183 | *primary_msg = msg;
1184 | *secondary_msg = NULL((void*)0);
1185 | } else {
1186 | /*
1187 | * Child process failed, but returned the expected exit status.
1188 | * Return the messages it gave us, and indicate failure.
1189 | */
1190 | *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1191 | *secondary_msg = g_strdup(secondary_msg_text)g_strdup_inline (secondary_msg_text);
1192 | ret = -1;
1193 | }
1194 | *data = NULL((void*)0);
1195 | break;
1196 |
1197 | case SP_BAD_FILTER'B': {
1198 | uint32_t indx = 0;
1199 | const char* end;
1200 |
1201 | if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
1202 | primary_msg_text = end + 1;
1203 | } else {
1204 | primary_msg_text = "dumpcap process returned a SP_BAD_FILTER without an error message";
1205 | }
1206 | /*
1207 | * Pick up the child status.
1208 | */
1209 | ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1210 | &fork_child, &msg);
1211 | if (ret == -1) {
1212 | /*
1213 | * Child process failed unexpectedly, or wait failed; msg is the
1214 | * error message.
1215 | */
1216 | *primary_msg = msg;
1217 | *secondary_msg = NULL((void*)0);
1218 | } else {
1219 | /*
1220 | * Child process failed, but returned the expected exit status.
1221 | * Return the messages it gave us, and indicate failure.
1222 | */
1223 | *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1224 | *secondary_msg = NULL((void*)0);
1225 | ret = -1;
1226 | }
1227 | *data = NULL((void*)0);
1228 | break;
1229 | }
1230 |
1231 | case SP_WARNING_MSG'W':
1232 | /*
1233 | * Warning from dumpcap; there will be a primary message and a
1234 | * secondary message.
1235 | *
1236 | * XXX - add a callback for these.
1237 | */
1238 | break;
1239 |
1240 | case SP_LOG_MSG'L':
1241 | /*
1242 | * Log from dumpcap; pass to our log
1243 | */
1244 | sync_pipe_handle_log_msg(buffer);
1245 | break;
1246 |
1247 | case SP_SUCCESS'S':
1248 | /* read the output from the command */
1249 | data_buf = g_string_new("");
1250 | while ((count = ws_readread(data_pipe_read_fd, buffer, PIPE_BUF_SIZE((512 * 1000)+4))) > 0) {
1251 | buffer[count] = '\0';
1252 | g_string_append(data_buf, buffer)(__builtin_constant_p (buffer) ? __extension__ ({ const char * const __val = (buffer); g_string_append_len_inline (data_buf , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (data_buf , buffer, (gssize) -1));
1253 | }
1254 |
1255 | /*
1256 | * Pick up the child status.
1257 | */
1258 | ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1259 | &fork_child, &msg);
1260 | if (ret == -1) {
1261 | /*
1262 | * Child process failed unexpectedly, or wait failed; msg is the
1263 | * error message.
1264 | */
1265 | *primary_msg = msg;
1266 | *secondary_msg = NULL((void*)0);
1267 | g_string_free(data_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (data_buf), ((!(0)))) : g_string_free_and_steal (data_buf)) : (g_string_free) ((data_buf), ((!(0)))));
1268 | *data = NULL((void*)0);
1269 | } else {
1270 | /*
1271 | * Child process succeeded.
1272 | */
1273 | *primary_msg = NULL((void*)0);
1274 | *secondary_msg = NULL((void*)0);
1275 | *data = g_string_free(data_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((data_buf ), ((0))) : g_string_free_and_steal (data_buf)) : (g_string_free ) ((data_buf), ((0))));
1276 | }
1277 | break;
1278 |
1279 | default:
1280 | /*
1281 | * Pick up the child status.
1282 | */
1283 | ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1284 | &fork_child, &msg);
1285 | if (ret == -1) {
1286 | /*
1287 | * Child process failed unexpectedly, or wait failed; msg is the
1288 | * error message.
1289 | */
1290 | *primary_msg = msg;
1291 | *secondary_msg = NULL((void*)0);
1292 | } else {
1293 | /*
1294 | * Child process returned an unknown status.
1295 | */
1296 | *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x" , indicator)
1297 | indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x" , indicator);
1298 | *secondary_msg = NULL((void*)0);
1299 | ret = -1;
1300 | }
1301 | *data = NULL((void*)0);
1302 | break;
1303 | }
1304 | } while (indicator != SP_SUCCESS'S' && ret != -1);
1305 |
1306 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1307 | return ret;
1308 | }
1309 |
1310 | /* centralised logging and timing for sync_pipe_run_command_actual(),
1311 | * redirects to sync_pipe_run_command_actual()
1312 | */
1313 | static int
1314 | sync_pipe_run_command(char **argv, char **data, char **primary_msg,
1315 | char **secondary_msg, void (*update_cb)(void))
1316 | {
1317 | int ret, i;
1318 | int64_t start_time;
1319 | double elapsed;
1320 | int logging_enabled;
1321 |
1322 | /* check if logging is actually enabled, otherwise don't expend the CPU generating logging */
1323 | logging_enabled = ws_log_msg_is_active(WS_LOG_DOMAIN"Capture", LOG_LEVEL_INFO);
1324 | if (logging_enabled) {
1325 | start_time = g_get_monotonic_time();
1326 | ws_debug("sync_pipe_run_command() starts")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1326, __func__, "sync_pipe_run_command() starts"); } } while (0);
1327 | for (i=0; argv[i] != 0; i++) {
1328 | ws_noisy(" argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_NOISY, "capture/capture_sync.c" , 1328, __func__, " argv[%d]: %s", i, argv[i]); } } while (0 );
1329 | }
1330 | }
1331 | /* do the actual sync pipe run command */
1332 | ret = sync_pipe_run_command_actual(argv, data, primary_msg, secondary_msg, update_cb);
1333 |
1334 | if (logging_enabled) {
1335 | elapsed = (g_get_monotonic_time() - start_time) / 1e6;
1336 |
1337 | ws_debug("sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1337, __func__, "sync_pipe_run_command() ends, taking %.3fs, result=%d" , elapsed, ret); } } while (0);
1338 |
1339 | }
1340 | return ret;
1341 | }
1342 |
1343 |
1344 | int
1345 | sync_interface_set_80211_chan(const char *iface, const char *freq, const char *type,
1346 | const char *center_freq1, const char *center_freq2,
1347 | char **data, char **primary_msg,
1348 | char **secondary_msg, void (*update_cb)(void))
1349 | {
1350 | int argc, ret;
1351 | char **argv;
1352 | char *opt;
1353 |
1354 | argv = init_pipe_args(&argc);
1355 |
1356 | if (!argv) {
1357 | *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1358 | *secondary_msg = NULL((void*)0);
1359 | *data = NULL((void*)0);
1360 | return -1;
1361 | }
1362 |
1363 | argv = sync_pipe_add_arg(argv, &argc, "-i");
1364 | argv = sync_pipe_add_arg(argv, &argc, iface);
1365 |
1366 | if (center_freq2)
1367 | opt = ws_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2)wmem_strdup_printf(((void*)0), "%s,%s,%s,%s", freq, type, center_freq1 , center_freq2);
1368 | else if (center_freq1)
1369 | opt = ws_strdup_printf("%s,%s,%s", freq, type, center_freq1)wmem_strdup_printf(((void*)0), "%s,%s,%s", freq, type, center_freq1 );
1370 | else if (type)
1371 | opt = ws_strdup_printf("%s,%s", freq, type)wmem_strdup_printf(((void*)0), "%s,%s", freq, type);
1372 | else
1373 | opt = g_strdup(freq)g_strdup_inline (freq);
1374 |
1375 | argv = sync_pipe_add_arg(argv, &argc, "-k");
1376 | argv = sync_pipe_add_arg(argv, &argc, opt);
1377 |
1378 | ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1379 | g_free(opt)(__builtin_object_size ((opt), 0) != ((size_t) - 1)) ? g_free_sized (opt, __builtin_object_size ((opt), 0)) : (g_free) (opt);
1380 | return ret;
1381 | }
1382 |
1383 | /*
1384 | * Get the results of compiling a capture filter for an interface using dumpcap.
1385 | *
1386 | * On success, *data points to a buffer containing the dumpcap output,
1387 | * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1388 | * must be freed with g_free().
1389 | *
1390 | * On failure, *data is NULL, *primary_msg points to an error message,
1391 | * *secondary_msg either points to an additional error message or is
1392 | * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1393 | * must be freed with g_free().
1394 | */
1395 | int
1396 | sync_if_bpf_filter_open(const char *ifname, const char* filter, int linktype,
1397 | bool_Bool optimize, char **data, char **primary_msg,
1398 | char **secondary_msg, void (*update_cb)(void))
1399 | {
1400 | int argc;
1401 | char **argv;
1402 | int ret;
1403 |
1404 | ws_debug("sync_if_bpf_filter_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1404, __func__, "sync_if_bpf_filter_open"); } } while (0);
1405 |
1406 | const char* linktype_name = linktype_val_to_name(linktype);
1407 | if (linktype != -1) { // Allow -1 for device default
1408 | if (!linktype_name) {
1409 | *primary_msg = g_strdup_printf("Unknown link-layer type %d.", linktype);
1410 | *secondary_msg = NULL((void*)0);
1411 | *data = NULL((void*)0);
1412 | return -1;
1413 | }
1414 | }
1415 |
1416 | argv = init_pipe_args(&argc);
1417 |
1418 | if (!argv) {
1419 | *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1420 | *secondary_msg = NULL((void*)0);
1421 | *data = NULL((void*)0);
1422 | return -1;
1423 | }
1424 |
1425 | /* Ask for the human-readable BPF code for the capture filter */
1426 | argv = sync_pipe_add_arg(argv, &argc, "-d");
1427 | argv = sync_pipe_add_arg(argv, &argc, "-i");
1428 | argv = sync_pipe_add_arg(argv, &argc, ifname);
1429 | if (linktype_name) {
1430 | argv = sync_pipe_add_arg(argv, &argc, "-y");
1431 | argv = sync_pipe_add_arg(argv, &argc, linktype_name);
1432 | }
1433 | if (!optimize) {
1434 | argv = sync_pipe_add_arg(argv, &argc, "--no-optimize");
1435 | }
1436 | if (filter && strcmp(filter, "") != 0) {
1437 | argv = sync_pipe_add_arg(argv, &argc, "-f");
1438 | argv = sync_pipe_add_arg(argv, &argc, filter);
1439 | }
1440 |
1441 | ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1442 | return ret;
1443 | }
1444 |
1445 | /*
1446 | * Get the list of interfaces using dumpcap.
1447 | *
1448 | * On success, *data points to a buffer containing the dumpcap output,
1449 | * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1450 | * must be freed with g_free().
1451 | *
1452 | * On failure, *data is NULL, *primary_msg points to an error message,
1453 | * *secondary_msg either points to an additional error message or is
1454 | * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1455 | * must be freed with g_free().
1456 | */
1457 | int
1458 | sync_interface_list_open(char **data, char **primary_msg,
1459 | char **secondary_msg, void (*update_cb)(void))
1460 | {
1461 | int argc;
1462 | char **argv;
1463 | int ret;
1464 |
1465 | ws_debug("sync_interface_list_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1465, __func__, "sync_interface_list_open"); } } while (0);
1466 |
1467 | argv = init_pipe_args(&argc);
1468 |
1469 | if (!argv) {
1470 | *primary_msg = g_strdup("We don't know where to find dumpcap..")g_strdup_inline ("We don't know where to find dumpcap..");
1471 | *secondary_msg = NULL((void*)0);
1472 | *data = NULL((void*)0);
1473 | return -1;
1474 | }
1475 |
1476 | /* Ask for the interface list */
1477 | argv = sync_pipe_add_arg(argv, &argc, "-D");
1478 |
1479 | ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1480 | return ret;
1481 | }
1482 |
1483 | /*
1484 | * Get the capabilities of an interface using dumpcap.
1485 | *
1486 | * On success, *data points to a buffer containing the dumpcap output,
1487 | * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1488 | * must be freed with g_free().
1489 | *
1490 | * On failure, *data is NULL, *primary_msg points to an error message,
1491 | * *secondary_msg either points to an additional error message or is
1492 | * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1493 | * must be freed with g_free().
1494 | */
1495 | int
1496 | sync_if_capabilities_open(const char *ifname, bool_Bool monitor_mode, const char* auth,
1497 | char **data, char **primary_msg,
1498 | char **secondary_msg, void (*update_cb)(void))
1499 | {
1500 | int argc;
1501 | char **argv;
1502 | int ret;
1503 |
1504 | ws_debug("sync_if_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1504, __func__, "sync_if_capabilities_open"); } } while (0);
1505 |
1506 | argv = init_pipe_args(&argc);
1507 |
1508 | if (!argv) {
1509 | *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1510 | *secondary_msg = NULL((void*)0);
1511 | *data = NULL((void*)0);
1512 | return -1;
1513 | }
1514 |
1515 | /* Ask for the interface capabilities */
1516 | argv = sync_pipe_add_arg(argv, &argc, "-i");
1517 | argv = sync_pipe_add_arg(argv, &argc, ifname);
1518 | argv = sync_pipe_add_arg(argv, &argc, "-L");
1519 | argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1520 | if (monitor_mode)
1521 | argv = sync_pipe_add_arg(argv, &argc, "-I");
1522 | if (auth) {
1523 | argv = sync_pipe_add_arg(argv, &argc, "-A");
1524 | argv = sync_pipe_add_arg(argv, &argc, auth);
1525 | }
1526 |
1527 | ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1528 | return ret;
1529 | }
1530 |
1531 | int
1532 | sync_if_list_capabilities_open(GList *if_queries, char **data,
1533 | char **primary_msg, char **secondary_msg,
1534 | void (*update_cb)(void))
1535 | {
1536 | int argc;
1537 | char **argv;
1538 | int ret;
1539 | if_cap_query_t *if_cap_query;
1540 |
1541 | ws_debug("sync_if_list_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1541, __func__, "sync_if_list_capabilities_open"); } } while (0);
1542 |
1543 | argv = init_pipe_args(&argc);
1544 |
1545 | if (!argv) {
1546 | *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1547 | *secondary_msg = NULL((void*)0);
1548 | *data = NULL((void*)0);
1549 | return -1;
1550 | }
1551 |
1552 | for (GList *li = if_queries; li != NULL((void*)0); li = g_list_next(li)((li) ? (((GList *)(li))->next) : ((void*)0))) {
1553 | if_cap_query = (if_cap_query_t*)li->data;
1554 | /* Ask for the interface capabilities */
1555 | argv = sync_pipe_add_arg(argv, &argc, "-i");
1556 | argv = sync_pipe_add_arg(argv, &argc, if_cap_query->name);
1557 | if (if_cap_query->monitor_mode)
1558 | argv = sync_pipe_add_arg(argv, &argc, "-I");
1559 | if (if_cap_query->auth_username && if_cap_query->auth_password) {
1560 | char sauth[256];
1561 | argv = sync_pipe_add_arg(argv, &argc, "-A");
1562 | snprintf(sauth, sizeof(sauth), "%s:%s",
1563 | if_cap_query->auth_username,
1564 | if_cap_query->auth_password);
1565 | argv = sync_pipe_add_arg(argv, &argc, sauth);
1566 | }
1567 | }
1568 | argv = sync_pipe_add_arg(argv, &argc, "-L");
1569 | argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1570 |
1571 | ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1572 | return ret;
1573 | }
1574 |
1575 | /*
1576 | * Start getting interface statistics using dumpcap. On success, read_fd
1577 | * contains the file descriptor for the pipe's stdout, *msg is unchanged,
1578 | * and zero is returned. On failure, *msg will point to an error message
1579 | * that must be g_free()d, and -1 will be returned.
1580 | * If data is not NULL, then it will also be set to point to a JSON
1581 | * serialization of the list of local interfaces and their capabilities.
1582 | */
1583 | int
1584 | sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **data, char **msg, void (*update_cb)(void))
1585 | {
1586 | int argc;
1587 | char **argv;
1588 | int ret;
1589 | GIOChannel *message_read_io;
1590 | char *wait_msg;
1591 | char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1592 | ssize_t nread;
1593 | char indicator;
1594 | int32_t exec_errno = 0;
1595 | unsigned primary_msg_len;
1596 | char *primary_msg_text;
1597 | unsigned secondary_msg_len;
1598 | /*char *secondary_msg_text;*/
1599 | char *combined_msg;
1600 |
1601 | ws_debug("sync_interface_stats_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1601, __func__, "sync_interface_stats_open"); } } while (0);
1602 |
1603 | argv = init_pipe_args(&argc);
1604 |
1605 | if (!argv) {
1606 | *msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1607 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1608 | return -1;
1609 | }
1610 |
1611 | /* Ask for the interface statistics */
1612 | argv = sync_pipe_add_arg(argv, &argc, "-S");
1613 |
1614 | /* If requested, ask for the interface list and capabilities. */
1615 | if (data) {
1616 | argv = sync_pipe_add_arg(argv, &argc, "-D");
1617 | argv = sync_pipe_add_arg(argv, &argc, "-L");
1618 | }
1619 |
1620 | #ifndef DEBUG_CHILD
1621 | #ifdef _WIN32
1622 | argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
1623 | ret = create_dummy_signal_pipe(msg);
1624 | if (ret == -1) {
1625 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1626 | return -1;
1627 | }
1628 | argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
1629 | #endif
1630 | #endif
1631 | ret = sync_pipe_open_command(argv, data_read_fd, &message_read_io, NULL((void*)0),
1632 | fork_child, NULL((void*)0), msg, update_cb);
1633 | if (ret == -1) {
1634 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1635 | return -1;
1636 | }
1637 |
1638 | /*
1639 | * We were able to set up to read dumpcap's output. Do so.
1640 | *
1641 | * First, wait for an SP_ERROR_MSG message or an SP_SUCCESS message.
1642 | */
1643 | do {
1644 | nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1645 | buffer, msg);
1646 | if(nread <= 0) {
1647 | /* We got a read error from the sync pipe, or we got no data at
1648 | all from the sync pipe, so we're not going to be getting any
1649 | data or error message from the child process. Pick up its
1650 | exit status, and complain.
1651 |
1652 | We don't have to worry about killing the child, if the sync pipe
1653 | returned an error. Usually this error is caused as the child killed
1654 | itself while going down. Even in the rare cases that this isn't the
1655 | case, the child will get an error when writing to the broken pipe
1656 | the next time, cleaning itself up then. */
1657 | g_io_channel_unref(message_read_io);
1658 | ws_closeclose(*data_read_fd);
1659 | ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
1660 | if(nread == 0) {
1661 | /* We got an EOF from the sync pipe. That means that it exited
1662 | before giving us any data to read. If ret is -1, we report
1663 | that as a bad exit (e.g., exiting due to a signal); otherwise,
1664 | we report it as a premature exit. */
1665 | if (ret == -1)
1666 | *msg = wait_msg;
1667 | else
1668 | *msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely" );
1669 | } else {
1670 | /* We got an error from the sync pipe. If ret is -1, report
1671 | both the sync pipe I/O error and the wait error. */
1672 | if (ret == -1) {
1673 | combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *msg, wait_msg);
1674 | g_free(*msg)(__builtin_object_size ((*msg), 0) != ((size_t) - 1)) ? g_free_sized (*msg, __builtin_object_size ((*msg), 0)) : (g_free) (*msg);
1675 | g_free(wait_msg)(__builtin_object_size ((wait_msg), 0) != ((size_t) - 1)) ? g_free_sized (wait_msg, __builtin_object_size ((wait_msg), 0)) : (g_free) (wait_msg);
1676 | *msg = combined_msg;
1677 | }
1678 | }
1679 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1680 | return -1;
1681 | }
1682 |
1683 | /* we got a valid message block from the child, process it */
1684 | switch(indicator) {
1685 |
1686 | case SP_EXEC_FAILED'X':
1687 | /*
1688 | * Exec of dumpcap failed. Get the errno for the failure.
1689 | */
1690 | if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1691 | ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 1691, __func__, "Invalid errno: %s", buffer); } } while (0);
1692 | }
1693 | *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno))
1694 | g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno));
1695 |
1696 | /*
1697 | * Pick up the child status.
1698 | */
1699 | char *close_msg = NULL((void*)0);
1700 | sync_pipe_close_command(data_read_fd, message_read_io,
1701 | fork_child, &close_msg);
1702 | /*
1703 | * Ignore the error from sync_pipe_close_command, presumably the one
1704 | * returned by the child is more pertinent to what went wrong.
1705 | */
1706 | g_free(close_msg)(__builtin_object_size ((close_msg), 0) != ((size_t) - 1)) ? g_free_sized (close_msg, __builtin_object_size ((close_msg), 0)) : (g_free ) (close_msg);
1707 | ret = -1;
1708 | break;
1709 |
1710 | case SP_ERROR_MSG'E':
1711 | /*
1712 | * Error from dumpcap; there will be a primary message and a
1713 | * secondary message.
1714 | */
1715 |
1716 | /* convert primary message */
1717 | pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1718 | primary_msg_text = buffer+4;
1719 | /* convert secondary message */
1720 | pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1721 | &secondary_msg_len);
1722 | /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
1723 | /* the capture child will close the sync_pipe, nothing to do */
1724 |
1725 | /*
1726 | * Pick up the child status.
1727 | */
1728 | ret = sync_pipe_close_command(data_read_fd, message_read_io,
1729 | fork_child, msg);
1730 | if (ret == -1) {
1731 | /*
1732 | * Child process failed unexpectedly, or wait failed; msg is the
1733 | * error message.
1734 | */
1735 | } else if (ret == WS_EXIT_NO_INTERFACES12) {
1736 | /*
1737 | * No interfaces were found. If that's not the
1738 | * result of an error when fetching the local
1739 | * interfaces, let the user know.
1740 | */
1741 | *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1742 | } else {
1743 | /*
1744 | * Child process failed, but returned the expected exit status.
1745 | * Return the messages it gave us, and indicate failure.
1746 | */
1747 | *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1748 | ret = -1;
1749 | }
1750 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1751 | return ret;
1752 |
1753 | case SP_LOG_MSG'L':
1754 | /*
1755 | * Log from dumpcap; pass to our log
1756 | */
1757 | sync_pipe_handle_log_msg(buffer);
1758 | break;
1759 |
1760 | case SP_WARNING_MSG'W':
1761 | /*
1762 | * Warning from dumpcap; there will be a primary message and a
1763 | * secondary message.
1764 | *
1765 | * XXX - add a callback for these.
1766 | */
1767 | break;
1768 |
1769 | case SP_IFACE_LIST'I':
1770 | /*
1771 | * Dumpcap giving us the interface list
1772 | */
1773 |
1774 | /* convert primary message */
1775 | if (data) {
1776 | *data = g_strdup(buffer)g_strdup_inline (buffer);
1777 | }
1778 | break;
1779 |
1780 | case SP_SUCCESS'S':
1781 | /* Close the message pipe. */
1782 | g_io_channel_unref(message_read_io);
1783 | break;
1784 |
1785 | default:
1786 | /*
1787 | * Pick up the child status.
1788 | */
1789 | ret = sync_pipe_close_command(data_read_fd, message_read_io,
1790 | fork_child, msg);
1791 | if (ret == -1) {
1792 | /*
1793 | * Child process failed unexpectedly, or wait failed; msg is the
1794 | * error message.
1795 | */
1796 | } else {
1797 | /*
1798 | * Child process returned an unknown status.
1799 | */
1800 | *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x" , indicator)
1801 | indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x" , indicator);
1802 | ret = -1;
1803 | }
1804 | break;
1805 | }
1806 | } while (indicator != SP_SUCCESS'S' && ret != -1);
1807 |
1808 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
1809 | return ret;
1810 | }
1811 |
1812 | /* Close down the stats process */
1813 | int
1814 | sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, char **msg)
1815 | {
1816 | #ifdef _WIN32
1817 | CloseHandle(dummy_signal_pipe);
1818 | dummy_signal_pipe = NULL((void*)0);
1819 | #else
1820 | /*
1821 | * Don't bother waiting for the child. sync_pipe_close_command
1822 | * does this for us on Windows.
1823 | */
1824 | sync_pipe_kill(*fork_child);
1825 | #endif
1826 | return sync_pipe_close_command(read_fd, NULL((void*)0), fork_child, msg);
1827 | }
1828 |
1829 | /* read a number of bytes from a pipe */
1830 | /* (blocks until enough bytes read or an error occurs) */
1831 | static ssize_t
1832 | pipe_read_bytes(GIOChannel *pipe_io, char *bytes, size_t required, char **msg)
1833 | {
1834 | GError *err = NULL((void*)0);
1835 | size_t newly;
1836 | size_t offset = 0;
1837 |
1838 | /*
1839 | * This should never happen, as "required" should be no greater than 2^24.
1840 | *
1841 | * XXX - 64-bit Haiku defines ssize_t as an signed long int but defines
1842 | * SSIZE_MAX as a signed long long int; they're the same width, but
1843 | * gcc warns of a type mismatch between %zd and signed long long int.
1844 | * We cast SSIZE_MAX to (ssize_t) to squelch the warning.
1845 | */
1846 | if (required > SSIZE_MAX9223372036854775807L) {
1847 | ws_debug("read from pipe %p: bytes to read %zu > %zd", pipe_io, required, (ssize_t)SSIZE_MAX)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1847, __func__, "read from pipe %p: bytes to read %zu > %zd" , pipe_io, required, (ssize_t)9223372036854775807L); } } while (0);
1848 | *msg = ws_strdup_printf("Error reading from sync pipe: bytes to read %zu > %zd", required, (ssize_t)SSIZE_MAX)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: bytes to read %zu > %zd" , required, (ssize_t)9223372036854775807L);
1849 | return -1;
1850 | }
1851 | while(required) {
1852 | if (g_io_channel_read_chars(pipe_io, &bytes[offset], required, &newly, &err) == G_IO_STATUS_ERROR) {
1853 | if (err != NULL((void*)0)) {
1854 | ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1854, __func__, "read from pipe %p: error(%u): %s", pipe_io , err->code, err->message); } } while (0);
1855 | *msg = ws_strdup_printf("Error reading from sync pipe: %s", err->message)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: %s" , err->message);
1856 | g_clear_error(&err);
1857 | } else {
1858 | ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1858, __func__, "read from pipe %p: unknown error", pipe_io ); } } while (0);
1859 | *msg = ws_strdup_printf("Error reading from sync pipe: unknown error")wmem_strdup_printf(((void*)0), "Error reading from sync pipe: unknown error" );
1860 | }
1861 | return -1;
1862 | }
1863 | if (newly == 0) {
1864 | /* EOF */
1865 | ws_debug("read from pipe %p: EOF (capture closed?)", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1865, __func__, "read from pipe %p: EOF (capture closed?)", pipe_io); } } while (0);
1866 | *msg = NULL((void*)0);
1867 | /*
1868 | * offset is, at this point, known to be less than the value of
1869 | * required passed to us, which is guaranteed to fit in an ssize_t.
1870 | */
1871 | return (ssize_t)offset;
1872 | }
1873 |
1874 | required -= newly;
1875 | offset += newly;
1876 | }
1877 |
1878 | /*
1879 | * offset is, at this point, known to be equal to the value of
1880 | * required passed to us, which is guaranteed to fit in an ssize_t.
1881 | */
1882 | *msg = NULL((void*)0);
1883 | return (ssize_t)offset;
1884 | }
1885 |
1886 | /*
1887 | * Read a line from a pipe; similar to fgets, but doesn't block.
1888 | *
1889 | * XXX - just stops reading if there's nothing to be read right now;
1890 | * that could conceivably mean that you don't get a complete line.
1891 | */
1892 | int
1893 | sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
1894 | ssize_t newly;
1895 | int offset = -1;
1896 |
1897 | while(offset < max - 1) {
1898 | offset++;
1899 | if (! ws_pipe_data_available(pipe_fd))
1900 | break;
1901 | newly = ws_readread(pipe_fd, &bytes[offset], 1);
1902 | if (newly == 0) {
1903 | /* EOF - not necessarily an error */
1904 | break;
1905 | } else if (newly == -1) {
1906 | /* error */
1907 | ws_debug("read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1907, __func__, "read from pipe %d: error(%u): %s", pipe_fd , (*__errno_location ()), g_strerror((*__errno_location ()))) ; } } while (0);
1908 | return -1;
1909 | } else if (bytes[offset] == '\n') {
1910 | break;
1911 | }
1912 | }
1913 |
1914 | if (offset >= 0)
1915 | bytes[offset] = '\0';
1916 |
1917 | return offset;
1918 | }
1919 |
1920 |
1921 | /* convert header values (indicator and 3-byte length) */
1922 | static void
1923 | pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len) {
1924 |
1925 | /* convert header values */
1926 | *indicator = pntohu8(&header[0]);
1927 | *block_len = pntohu24(&header[1]);
1928 | }
1929 |
1930 | /* read a message from the sending pipe in the standard format
1931 | (1-byte message indicator, 3-byte message length (excluding length
1932 | and indicator field), and the rest is the message) */
1933 | static ssize_t
1934 | pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
1935 | char **err_msg)
1936 | {
1937 | unsigned required;
1938 | ssize_t newly;
1939 | char header[4];
1940 |
1941 | /* read header (indicator and 3-byte length) */
1942 | newly = pipe_read_bytes(pipe_io, header, 4, err_msg);
1943 | if(newly != 4) {
1944 | if(newly == -1) {
1945 | /*
1946 | * Error; *err_msg has been set.
1947 | */
1948 | ws_debug("read %p got an error reading header: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1948, __func__, "read %p got an error reading header: %s", pipe_io , *err_msg); } } while (0);
1949 | return -1;
1950 | }
1951 | if(newly == 0) {
1952 | /*
1953 | * Immediate EOF; if the capture child exits normally, this
1954 | * is an "I'm done" indication, so don't report it as an
1955 | * error.
1956 | */
1957 | ws_debug("read %p got an EOF reading header", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1957, __func__, "read %p got an EOF reading header", pipe_io ); } } while (0);
1958 | return 0;
1959 | }
1960 | /*
1961 | * Short read, but not an immediate EOF.
1962 | */
1963 | ws_debug("read %p got premature EOF reading header: %zd", pipe_io, newly)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1963, __func__, "read %p got premature EOF reading header: %zd" , pipe_io, newly); } } while (0);
1964 | *err_msg = ws_strdup_printf("Premature EOF reading from sync pipe: got only %zd bytes",wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes" , newly)
1965 | newly)wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes" , newly);
1966 | return -1;
1967 | }
1968 |
1969 | /* convert header values */
1970 | pipe_convert_header((unsigned char*)header, indicator, &required);
1971 |
1972 | /* only indicator with no value? */
1973 | if(required == 0) {
1974 | ws_debug("read %p indicator: %c empty value", pipe_io, *indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1974, __func__, "read %p indicator: %c empty value", pipe_io , *indicator); } } while (0);
1975 | return 4;
1976 | }
1977 |
1978 | /* does the data fit into the given buffer? */
1979 | if(required > len) {
1980 | size_t bytes_read;
1981 | GError *err = NULL((void*)0);
1982 | ws_debug("read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1984, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x" , pipe_io, required, len, header[0], header[1], header[2], header [3]); } } while (0)
1983 | pipe_io, required, len,do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1984, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x" , pipe_io, required, len, header[0], header[1], header[2], header [3]); } } while (0)
1984 | header[0], header[1], header[2], header[3])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1984, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x" , pipe_io, required, len, header[0], header[1], header[2], header [3]); } } while (0);
1985 |
1986 | /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
1987 | if (g_io_channel_read_chars(pipe_io, msg, len, &bytes_read, &err) == G_IO_STATUS_ERROR) {
1988 | if (err != NULL((void*)0)) { /* error */
1989 | ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1989, __func__, "read from pipe %p: error(%u): %s", pipe_io , err->code, err->message); } } while (0);
1990 | g_clear_error(&err);
1991 | } else {
1992 | ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 1992, __func__, "read from pipe %p: unknown error", pipe_io ); } } while (0);
1993 | }
1994 | }
1995 | *err_msg = ws_strdup_printf("Message %c from dumpcap with length %d > buffer size %d! Partial message: %s",wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s" , *indicator, required, len, msg)
1996 | *indicator, required, len, msg)wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s" , *indicator, required, len, msg);
1997 | return -1;
1998 | }
1999 | len = required;
2000 |
2001 | /* read the actual block data */
2002 | newly = pipe_read_bytes(pipe_io, msg, required, err_msg);
2003 | if(newly == -1) {
2004 | /*
2005 | * Error; *err_msg has been set.
2006 | */
2007 | ws_debug("read %p got an error reading block data: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2007, __func__, "read %p got an error reading block data: %s" , pipe_io, *err_msg); } } while (0);
2008 | return -1;
2009 | }
2010 |
2011 | /*
2012 | * newly is guaranteed to be >= 0 at this point, as pipe_read_bytes()
2013 | * either returns -1 on an error, a positive value <= required on
2014 | * a short read, or required on a non-short read.
2015 | */
2016 | if((size_t)newly != required) {
2017 | *err_msg = ws_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s" , msg)
2018 | msg)wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s" , msg);
2019 | return -1;
2020 | }
2021 |
2022 | /* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
2023 | ws_debug("read %p ok indicator: %c len: %u msg: %s", pipe_io, *indicator, len, msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2023, __func__, "read %p ok indicator: %c len: %u msg: %s", pipe_io, *indicator, len, msg); } } while (0);
2024 | *err_msg = NULL((void*)0);
2025 | return newly + 4;
2026 | }
2027 |
2028 |
2029 | /* There's stuff to read from the sync pipe, meaning the child has sent
2030 | us a message, or the sync pipe has closed, meaning the child has
2031 | closed it (perhaps because it exited). */
2032 | static bool_Bool
2033 | sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
2034 | {
2035 | int ret;
2036 | char *buffer = g_malloc(SP_MAX_MSG_LEN(512 * 1000) + 1);
2037 | ssize_t nread;
2038 | char indicator;
2039 | int32_t exec_errno = 0;
2040 | unsigned primary_len;
2041 | char *primary_msg;
2042 | unsigned secondary_len;
2043 | char *secondary_msg;
2044 | char *wait_msg, *combined_msg;
2045 | uint32_t npackets = 0;
2046 |
2047 | nread = pipe_read_block(pipe_io, &indicator, SP_MAX_MSG_LEN(512 * 1000), buffer,
2048 | &primary_msg);
2049 | if(nread <= 0) {
2050 | /* We got a read error, or a bad message, or an EOF, from the sync pipe.
2051 |
2052 | If we got a read error or a bad message, nread is -1 and
2053 | primary_msg is set to point to an error message. We don't
2054 | have to worry about killing the child; usually this error
2055 | is caused as the child killed itself while going down.
2056 | Even in the rare cases that this isn't the case, the child
2057 | will get an error when writing to the broken pipe the next time,
2058 | cleaning itself up then.
2059 |
2060 | If we got an EOF, nread is 0 and primary_msg isn't set. This
2061 | is an indication that the capture is finished. */
2062 | ret = sync_pipe_wait_for_child(cap_session->fork_child, &wait_msg);
2063 | if(nread == 0) {
2064 | /* We got an EOF from the sync pipe. That means that the capture
2065 | child exited, and not in the middle of a message; we treat
2066 | that as an indication that it's done, and only report an
2067 | error if ret is -1, in which case wait_msg is the error
2068 | message. */
2069 | if (ret == -1)
2070 | primary_msg = wait_msg;
2071 | } else {
2072 | /* We got an error from the sync pipe. If ret is -1, report
2073 | both the sync pipe I/O error and the wait error. */
2074 | if (ret == -1) {
2075 | combined_msg = ws_strdup_printf("%s\n\n%s", primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", primary_msg, wait_msg );
2076 | g_free(primary_msg)(__builtin_object_size ((primary_msg), 0) != ((size_t) - 1)) ? g_free_sized (primary_msg, __builtin_object_size ((primary_msg ), 0)) : (g_free) (primary_msg);
2077 | g_free(wait_msg)(__builtin_object_size ((wait_msg), 0) != ((size_t) - 1)) ? g_free_sized (wait_msg, __builtin_object_size ((wait_msg), 0)) : (g_free) (wait_msg);
2078 | primary_msg = combined_msg;
2079 | }
2080 | }
2081 |
2082 | /* No more child process. */
2083 | cap_session->fork_child = WS_INVALID_PID-1;
2084 | cap_session->fork_child_status = ret;
2085 |
2086 | #ifdef _WIN32
2087 | ws_closeclose(cap_session->signal_pipe_write_fd);
2088 | #endif
2089 | cap_session->capture_opts->closed_msg = primary_msg;
2090 | if (extcap_session_stop(cap_session)) {
2091 | capture_process_finished(cap_session);
2092 | } else {
2093 | extcap_request_stop(cap_session);
2094 | }
2095 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
2096 | return false0;
2097 | }
2098 |
2099 | /* we got a valid message block from the child, process it */
2100 | switch(indicator) {
2101 | case SP_FILE'F':
2102 | if(!cap_session->new_file(cap_session, buffer)) {
2103 | ws_debug("file failed, closing capture")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2103, __func__, "file failed, closing capture"); } } while ( 0);
2104 |
2105 | /* We weren't able to open the new capture file; user has been
2106 | alerted. The sync pipe will close after we return false. */
2107 |
2108 | /* The child has sent us a filename which we couldn't open.
2109 |
2110 | This could mean that the child is creating and deleting files
2111 | (ring buffer mode) faster than we can handle it.
2112 |
2113 | That should only be the case for very fast file switches;
2114 | We can't do much more than telling the child to stop.
2115 | (This is the "emergency brake" if the user e.g. wants to
2116 | switch files every second).
2117 |
2118 | This can also happen if the user specified "-", meaning
2119 | "standard output", as the capture file. */
2120 | sync_pipe_stop(cap_session);
2121 | cap_session->closed(cap_session, NULL((void*)0));
2122 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
2123 | return false0;
2124 | }
2125 | break;
2126 | case SP_PACKET_COUNT'P':
2127 | if (!ws_strtou32(buffer, NULL((void*)0), &npackets)) {
2128 | ws_warning("Invalid packets number: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2128, __func__, "Invalid packets number: %s", buffer); } } while (0);
2129 | }
2130 | ws_debug("new packets %u", npackets)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2130, __func__, "new packets %u", npackets); } } while (0);
2131 | cap_session->count += npackets;
2132 | cap_session->new_packets(cap_session, npackets);
2133 | break;
2134 | case SP_EXEC_FAILED'X':
2135 | /*
2136 | * Exec of dumpcap failed. Get the errno for the failure.
2137 | */
2138 | if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
2139 | ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2139, __func__, "Invalid errno: %s", buffer); } } while (0);
2140 | }
2141 | primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno))
2142 | g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s" , g_strerror(exec_errno));
2143 | cap_session->error(cap_session, primary_msg, NULL((void*)0));
2144 | /* the capture child will close the sync_pipe, nothing to do for now */
2145 | /* (an error message doesn't mean we have to stop capturing) */
2146 | break;
2147 | case SP_ERROR_MSG'E':
2148 | case SP_WARNING_MSG'W':
2149 | /* convert primary message */
2150 | pipe_convert_header((unsigned char*)buffer, &indicator, &primary_len);
2151 | primary_msg = buffer+4;
2152 | /* convert secondary message */
2153 | pipe_convert_header((unsigned char*)primary_msg + primary_len, &indicator, &secondary_len);
2154 | secondary_msg = primary_msg + primary_len + 4;
2155 | /* message output */
2156 | if (indicator == SP_WARNING_MSG'W')
2157 | cap_session->warning(cap_session, primary_msg, secondary_msg);
2158 | else
2159 | cap_session->error(cap_session, primary_msg, secondary_msg);
2160 | /* the capture child will close the sync_pipe, nothing to do for now */
2161 | /* (an error message doesn't mean we have to stop capturing) */
2162 | break;
2163 | case SP_LOG_MSG'L':
2164 | /*
2165 | * Log from dumpcap; pass to our log
2166 | */
2167 | sync_pipe_handle_log_msg(buffer);
2168 | break;
2169 | case SP_BAD_FILTER'B': {
2170 | const char *message=NULL((void*)0);
2171 | uint32_t indx = 0;
2172 | const char* end;
2173 |
2174 | if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
2175 | message = end + 1;
2176 | }
2177 |
2178 | cap_session->cfilter_error(cap_session, indx, message);
2179 | /* the capture child will close the sync_pipe, nothing to do for now */
2180 | break;
2181 | }
2182 | case SP_DROPS'D': {
2183 | const char *name = NULL((void*)0);
2184 | const char* end;
2185 | uint32_t num = 0;
2186 |
2187 | if (ws_strtou32(buffer, &end, &num) && end[0] == ':') {
2188 | name = end + 1;
2189 | }
2190 |
2191 | cap_session->drops(cap_session, num, name);
2192 | break;
2193 | }
2194 | default:
2195 | if (g_ascii_isprint(indicator)((g_ascii_table[(guchar) (indicator)] & G_ASCII_PRINT) != 0))
2196 | ws_warning("Unknown indicator '%c'", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2196, __func__, "Unknown indicator '%c'", indicator); } } while (0);
2197 | else
2198 | ws_warning("Unknown indicator '\\x%02x", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2198, __func__, "Unknown indicator '\\x%02x", indicator); } } while (0);
2199 | break;
2200 | }
2201 |
2202 | g_free(buffer)(__builtin_object_size ((buffer), 0) != ((size_t) - 1)) ? g_free_sized (buffer, __builtin_object_size ((buffer), 0)) : (g_free) (buffer );
2203 | return true1;
2204 | }
2205 |
2206 |
2207 |
2208 | /*
2209 | * dumpcap is exiting; wait for it to exit. On success, *msgp is
2210 | * unchanged, and the exit status of dumpcap is returned. On
2211 | * failure (which includes "dumpcap exited due to being killed by
2212 | * a signal or an exception"), *msgp points to an error message
2213 | * for the failure, and -1 is returned. In the latter case, *msgp
2214 | * must be freed with g_free().
2215 | */
2216 | static int
2217 | sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp)
2218 | {
2219 | int fork_child_status;
2220 | #ifndef _WIN32
2221 | int retry_waitpid = 3;
2222 | #endif
2223 | int ret = -1;
2224 | int64_t start_time;
2225 | double elapsed;
2226 |
2227 | start_time = g_get_monotonic_time();
2228 |
2229 | ws_debug("wait till child closed")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2229, __func__, "wait till child closed"); } } while (0);
2230 | ws_assert(fork_child != WS_INVALID_PID)do { if ((1) && !(fork_child != -1)) ws_log_fatal_full ("Capture", LOG_LEVEL_ERROR, "capture/capture_sync.c", 2230, __func__ , "assertion failed: %s", "fork_child != -1"); } while (0);
2231 |
2232 | *msgp = NULL((void*)0); /* assume no error */
2233 | #ifdef _WIN32
2234 | if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
2235 | *msgp = ws_strdup_printf("Error from cwait(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from cwait(): %s", g_strerror ((*__errno_location ())));
2236 | ret = -1;
2237 | } else {
2238 | /*
2239 | * The child exited; return its exit status. Do not treat this as
2240 | * an error.
2241 | */
2242 | ret = fork_child_status;
2243 | if ((fork_child_status & 0xC0000000) == ERROR_SEVERITY_ERROR) {
2244 | /* Probably an exception code */
2245 | *msgp = ws_strdup_printf("Child dumpcap process died: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s" , win32strexception(fork_child_status))
2246 | win32strexception(fork_child_status))wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s" , win32strexception(fork_child_status));
2247 | ret = -1;
2248 | }
2249 | }
2250 | #else
2251 | while (--retry_waitpid >= 0) {
2252 | if (waitpid(fork_child, &fork_child_status, 0) != -1) {
2253 | /* waitpid() succeeded */
2254 | if (WIFEXITED(fork_child_status)(((fork_child_status) & 0x7f) == 0)) {
2255 | /*
2256 | * The child exited; return its exit status. Do not treat this as
2257 | * an error.
2258 | */
2259 | ret = WEXITSTATUS(fork_child_status)(((fork_child_status) & 0xff00) >> 8);
2260 | } else if (WIFSTOPPED(fork_child_status)(((fork_child_status) & 0xff) == 0x7f)) {
2261 | /* It stopped, rather than exiting. "Should not happen." */
2262 | *msgp = ws_strdup_printf("Child dumpcap process stopped: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s" , sync_pipe_signame((((fork_child_status) & 0xff00) >> 8)))
2263 | sync_pipe_signame(WSTOPSIG(fork_child_status)))wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s" , sync_pipe_signame((((fork_child_status) & 0xff00) >> 8)));
2264 | ret = -1;
2265 | } else if (WIFSIGNALED(fork_child_status)(((signed char) (((fork_child_status) & 0x7f) + 1) >> 1) > 0)) {
2266 | /* It died with a signal. */
2267 | *msgp = ws_strdup_printf("Child dumpcap process died: %s%s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s" , sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status ) & 0x80) ? " - core dumped" : "")
2268 | sync_pipe_signame(WTERMSIG(fork_child_status)),wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s" , sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status ) & 0x80) ? " - core dumped" : "")
2269 | WCOREDUMP(fork_child_status) ? " - core dumped" : "")wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s" , sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status ) & 0x80) ? " - core dumped" : "");
2270 | ret = -1;
2271 | } else {
2272 | /* What? It had to either have exited, or stopped, or died with
2273 | a signal; what happened here? */
2274 | *msgp = ws_strdup_printf("Bad status from waitpid(): %#o",wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o" , fork_child_status)
2275 | fork_child_status)wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o" , fork_child_status);
2276 | ret = -1;
2277 | }
2278 | } else {
2279 | /* waitpid() failed */
2280 | if (errno(*__errno_location ()) == EINTR4) {
2281 | /*
2282 | * Signal interrupted waitpid().
2283 | *
2284 | * If it's SIGALRM, we just want to keep waiting, in case
2285 | * there's some timer using it (e.g., in a GUI toolkit).
2286 | *
2287 | * If you ^C TShark (or Wireshark), that should deliver
2288 | * SIGINT to dumpcap as well. dumpcap catches SIGINT,
2289 | * and should clean up and exit, so we should eventually
2290 | * see that and clean up and terminate.
2291 | *
2292 | * If we're sent a SIGTERM, we should (and do) catch it,
2293 | * and TShark, at least, calls sync_pipe_stop(). which
2294 | * kills dumpcap, so we should eventually see that and
2295 | * clean up and terminate.
2296 | */
2297 | ws_warning("waitpid returned EINTR. retrying.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2297, __func__, "waitpid returned EINTR. retrying."); } } while (0);
2298 | continue;
2299 | } else if (errno(*__errno_location ()) == ECHILD10) {
2300 | /*
2301 | * The process identified by fork_child either doesn't
2302 | * exist any more or isn't our child process (anymore?).
2303 | *
2304 | * echld might have already reaped the child.
2305 | */
2306 | ret = fetch_dumpcap_pid ? 0 : -1;
2307 | } else {
2308 | /* Unknown error. */
2309 | *msgp = ws_strdup_printf("Error from waitpid(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from waitpid(): %s", g_strerror ((*__errno_location ())));
2310 | ret = -1;
2311 | }
2312 | }
2313 | break;
2314 | }
2315 | #endif
2316 |
2317 | elapsed = (g_get_monotonic_time() - start_time) / 1e6;
2318 | ws_debug("capture child closed after %.3fs", elapsed)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2318, __func__, "capture child closed after %.3fs", elapsed ); } } while (0);
2319 | return ret;
2320 | }
2321 |
2322 |
2323 | #ifndef _WIN32
2324 | /* convert signal to corresponding name */
2325 | static const char *
2326 | sync_pipe_signame(int sig)
2327 | {
2328 | const char *sigmsg;
2329 | static WS_THREAD_LOCAL__thread char sigmsg_buf[6+1+1+10+1];
2330 |
2331 | switch (sig) {
2332 |
2333 | case SIGHUP1:
2334 | sigmsg = "Hangup";
2335 | break;
2336 |
2337 | case SIGINT2:
2338 | sigmsg = "Interrupted";
2339 | break;
2340 |
2341 | case SIGQUIT3:
2342 | sigmsg = "Quit";
2343 | break;
2344 |
2345 | case SIGILL4:
2346 | sigmsg = "Illegal instruction";
2347 | break;
2348 |
2349 | case SIGTRAP5:
2350 | sigmsg = "Trace trap";
2351 | break;
2352 |
2353 | case SIGABRT6:
2354 | sigmsg = "Abort";
2355 | break;
2356 |
2357 | case SIGFPE8:
2358 | sigmsg = "Arithmetic exception";
2359 | break;
2360 |
2361 | case SIGKILL9:
2362 | sigmsg = "Killed";
2363 | break;
2364 |
2365 | case SIGBUS7:
2366 | sigmsg = "Bus error";
2367 | break;
2368 |
2369 | case SIGSEGV11:
2370 | sigmsg = "Segmentation violation";
2371 | break;
2372 |
2373 | /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
2374 | Linux is POSIX compliant. These are not POSIX-defined signals ---
2375 | ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
2376 |
2377 | ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
2378 | were omitted from POSIX.1 because their behavior is
2379 | implementation dependent and could not be adequately catego-
2380 | rized. Conforming implementations may deliver these sig-
2381 | nals, but must document the circumstances under which they
2382 | are delivered and note any restrictions concerning their
2383 | delivery.''
2384 |
2385 | So we only check for SIGSYS on those systems that happen to
2386 | implement them (a system can be POSIX-compliant and implement
2387 | them, it's just that POSIX doesn't *require* a POSIX-compliant
2388 | system to implement them).
2389 | */
2390 |
2391 | #ifdef SIGSYS31
2392 | case SIGSYS31:
2393 | sigmsg = "Bad system call";
2394 | break;
2395 | #endif
2396 |
2397 | case SIGPIPE13:
2398 | sigmsg = "Broken pipe";
2399 | break;
2400 |
2401 | case SIGALRM14:
2402 | sigmsg = "Alarm clock";
2403 | break;
2404 |
2405 | case SIGTERM15:
2406 | sigmsg = "Terminated";
2407 | break;
2408 |
2409 | default:
2410 | /* Returning a static buffer is ok in the context we use it here */
2411 | snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
2412 | sigmsg = sigmsg_buf;
2413 | break;
2414 | }
2415 | return sigmsg;
2416 | }
2417 | #endif
2418 |
2419 |
2420 | #ifdef _WIN32
2421 |
2422 | static int create_dummy_signal_pipe(char **msg) {
2423 | char *dummy_signal_pipe_name;
2424 |
2425 | if (dummy_signal_pipe != NULL((void*)0)) return 0;
2426 |
2427 | if (!dummy_control_id) {
2428 | dummy_control_id = ws_strdup_printf("%ld.dummy", GetCurrentProcessId())wmem_strdup_printf(((void*)0), "%ld.dummy", GetCurrentProcessId ());
2429 | }
2430 |
2431 | /* Create the signal pipe */
2432 | dummy_signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, dummy_control_id );
2433 | dummy_signal_pipe = CreateNamedPipe(utf_8to16(dummy_signal_pipe_name),
2434 | PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
2435 | g_free(dummy_signal_pipe_name)(__builtin_object_size ((dummy_signal_pipe_name), 0) != ((size_t ) - 1)) ? g_free_sized (dummy_signal_pipe_name, __builtin_object_size ((dummy_signal_pipe_name), 0)) : (g_free) (dummy_signal_pipe_name );
2436 | if (dummy_signal_pipe == INVALID_HANDLE_VALUE) {
2437 | *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s" , win32strerror(GetLastError()))
2438 | win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s" , win32strerror(GetLastError()));
2439 | return -1;
2440 | }
2441 | return 0;
2442 | }
2443 |
2444 | /* tell the child through the signal pipe that we want to quit the capture */
2445 | static void
2446 | signal_pipe_capquit_to_child(capture_session *cap_session)
2447 | {
2448 | const char quit_msg[] = "QUIT";
2449 | int ret;
2450 |
2451 | ws_debug("signal_pipe_capquit_to_child")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2451, __func__, "signal_pipe_capquit_to_child"); } } while ( 0);
2452 |
2453 | /* it doesn't matter *what* we send here, the first byte will stop the capture */
2454 | /* simply sending a "QUIT" string */
2455 | /*sync_pipe_write_string_msg(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
2456 | ret = ws_writewrite(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
2457 | if(ret == -1) {
2458 | DWORD lastError = GetLastError();
2459 | switch (lastError) {
2460 | case ERROR_NO_DATA:
2461 | /* "The pipe is being closed." - This is a normal condition in
2462 | * this situation. */
2463 | ws_debug("%s", win32strerror(lastError))do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c" , 2463, __func__, "%s", win32strerror(lastError)); } } while ( 0);
2464 | break;
2465 | default:
2466 | ws_warning("%d header: error %s", cap_session->signal_pipe_write_fd, win32strerror(lastError))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2466, __func__, "%d header: error %s", cap_session->signal_pipe_write_fd , win32strerror(lastError)); } } while (0);
2467 | }
2468 | }
2469 | }
2470 | #endif
2471 |
2472 |
2473 | /* user wants to stop the capture run */
2474 | void
2475 | sync_pipe_stop(capture_session *cap_session)
2476 | {
2477 | if (cap_session->fork_child != WS_INVALID_PID-1) {
2478 | #ifndef _WIN32
2479 | /* send the SIGINT signal to close the capture child gracefully. */
2480 | int sts = kill(cap_session->fork_child, SIGINT2);
2481 | if (sts != 0) {
2482 | ws_warning("Sending SIGINT to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2482, __func__, "Sending SIGINT to child failed: %s\n", g_strerror ((*__errno_location ()))); } } while (0);
2483 | }
2484 | #else
2485 | #define STOP_SLEEP_TIME 500 /* ms */
2486 | DWORD status;
2487 |
2488 | /* First, use the special signal pipe to try to close the capture child
2489 | * gracefully.
2490 | */
2491 | signal_pipe_capquit_to_child(cap_session);
2492 |
2493 | /* Next, wait for the process to exit on its own */
2494 | status = WaitForSingleObject((HANDLE) cap_session->fork_child, STOP_SLEEP_TIME);
2495 |
2496 | /* Force the issue. */
2497 | if (status != WAIT_OBJECT_0) {
2498 | ws_warning("sync_pipe_stop: forcing child to exit")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2498, __func__, "sync_pipe_stop: forcing child to exit"); } } while (0);
2499 | sync_pipe_kill(cap_session->fork_child);
2500 | }
2501 | #endif
2502 | }
2503 | }
2504 |
2505 |
2506 | /* Wireshark has to exit, force the capture child to close */
2507 | void
2508 | sync_pipe_kill(ws_process_id fork_child)
2509 | {
2510 | if (fork_child != WS_INVALID_PID-1) {
2511 | #ifndef _WIN32
2512 | int sts = kill(fork_child, SIGTERM15); /* SIGTERM so it can clean up if necessary */
2513 | if (sts != 0) {
2514 | ws_warning("Sending SIGTERM to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c" , 2514, __func__, "Sending SIGTERM to child failed: %s\n", g_strerror ((*__errno_location ()))); } } while (0);
2515 | }
2516 | #else
2517 | /* Remark: This is not the preferred method of closing a process!
2518 | * the clean way would be getting the process id of the child process,
2519 | * then getting window handle hWnd of that process (using EnumChildWindows),
2520 | * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
2521 | *
2522 | * Unfortunately, I don't know how to get the process id from the
2523 | * handle. OpenProcess will get an handle (not a window handle)
2524 | * from the process ID; it will not get a window handle from the
2525 | * process ID. (How could it? A process can have more than one
2526 | * window. For that matter, a process might have *no* windows,
2527 | * as a process running dumpcap, the normal child process program,
2528 | * probably does.)
2529 | *
2530 | * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
2531 | * running in the same console; that's not necessarily the case for
2532 | * us, as we might not be running in a console.
2533 | * And this also will require to have the process id.
2534 | */
2535 | TerminateProcess((HANDLE) (fork_child), 0);
2536 |
2537 | #endif
2538 | }
2539 | }
2540 |
2541 | void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid)) {
2542 | fetch_dumpcap_pid = cb;
2543 | }
2544 |
2545 | #endif /* HAVE_LIBPCAP */