Rename Windows ConsoleCtrHandlerRoutine --> capture_cleanup to match SVN #23537 change
[metze/wireshark/wip.git] / dumpcap.c
1 /* dumpcap.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <stdlib.h> /* for exit() */
29 #include <glib.h>
30
31 #include <string.h>
32 #include <ctype.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <signal.h>
39
40 #ifdef NEED_GETOPT_H
41 #include "getopt.h"
42 #endif
43
44 #ifdef HAVE_NETDB_H
45 #include <netdb.h>
46 #endif
47
48 #ifdef HAVE_LIBCAP
49 # include <sys/prctl.h>
50 # include <sys/capability.h>
51 # include <stdio.h>
52 #endif
53
54 #include "ringbuffer.h"
55 #include "clopts_common.h"
56 #include "cmdarg_err.h"
57 #include "version_info.h"
58
59 #include <pcap.h>
60 #include "capture-pcap-util.h"
61
62 #ifdef _WIN32
63 #include "capture-wpcap.h"
64 #endif
65
66 #ifdef _WIN32
67 #include "epan/unicode-utils.h"
68 #endif
69
70 #ifdef HAVE_LIBCAP
71 #include "epan/privileges.h"
72 #endif
73
74 #include "sync_pipe.h"
75
76 #include "capture.h"
77 #include "capture_loop.h"
78 #include "capture_sync.h"
79
80 #include "simple_dialog.h"
81 #include "util.h"
82 #include "log.h"
83 #include "file_util.h"
84
85
86 /*#define DEBUG_DUMPCAP*/
87
88 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
89 #ifdef _WIN32
90 gchar *sig_pipe_name = NULL;
91 HANDLE sig_pipe_handle = NULL;
92 #endif
93
94 static void
95 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
96                     const char *message, gpointer user_data _U_);
97
98 /* capture related options */
99 capture_options global_capture_opts;
100 capture_options *capture_opts = &global_capture_opts;
101
102 #if __GNUC__ >= 2
103 void exit_main(int err) __attribute__ ((noreturn));
104 #else
105 void exit_main(int err);
106 #endif
107
108
109 static void
110 print_usage(gboolean print_ver) {
111
112   FILE *output;
113
114
115   if (print_ver) {
116     output = stdout;
117     fprintf(output,
118         "Dumpcap " VERSION "%s\n"
119         "Capture network packets and dump them into a libpcap file.\n"
120         "See http://www.wireshark.org for more information.\n",
121         wireshark_svnversion);
122   } else {
123     output = stderr;
124   }
125   fprintf(output, "\nUsage: dumpcap [options] ...\n");
126   fprintf(output, "\n");
127   fprintf(output, "Capture interface:\n");
128   fprintf(output, "  -i <interface>           name or idx of interface (def: first none loopback)\n");
129   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
130   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
131   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
132 #ifdef _WIN32
133   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
134 #endif
135   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
136   fprintf(output, "  -D                       print list of interfaces and exit\n");
137   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
138   fprintf(output, "  -S                       print statistics for each interface once every second\n");
139   fprintf(output, "  -M                       for -D, -L, and -S produce machine-readable output\n");
140   fprintf(output, "\n");
141   fprintf(output, "Stop conditions:\n");
142   fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
143   fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
144   fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
145   fprintf(output, "                              files:NUM - stop after NUM files\n");
146   /*fprintf(output, "\n");*/
147   fprintf(output, "Output (files):\n");
148   fprintf(output, "  -w <filename>            name of file to save (def: tempfile)\n");
149   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
150   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
151   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
152   /*fprintf(output, "\n");*/
153   fprintf(output, "Miscellaneous:\n");
154   fprintf(output, "  -v                       print version information and exit\n");
155   fprintf(output, "  -h                       display this help and exit\n");
156   fprintf(output, "\n");
157   fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
158   fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
159   fprintf(output, "\n");
160   fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
161 }
162
163 static void
164 show_version(GString *comp_info_str, GString *runtime_info_str)
165 {
166
167   printf(
168         "Dumpcap " VERSION "%s\n"
169         "\n"
170         "%s\n"
171         "%s\n"
172         "%s\n"
173         "See http://www.wireshark.org for more information.\n",
174         wireshark_svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
175 }
176
177 /*
178  * Report an error in command-line arguments.
179  */
180 void
181 cmdarg_err(const char *fmt, ...)
182 {
183   va_list ap;
184
185   if(capture_child) {
186     /* Print a bare error */
187     va_start(ap, fmt);
188     vfprintf(stderr, fmt, ap);
189     va_end(ap);
190   } else {
191     va_start(ap, fmt);
192     fprintf(stderr, "dumpcap: ");
193     vfprintf(stderr, fmt, ap);
194     fprintf(stderr, "\n");
195     va_end(ap);
196   }
197 }
198
199 /*
200  * Report additional information for an error in command-line arguments.
201  */
202 void
203 cmdarg_err_cont(const char *fmt, ...)
204 {
205   va_list ap;
206
207   if(capture_child) {
208     /* XXX - convert to g_log */
209   } else {
210     va_start(ap, fmt);
211     vfprintf(stderr, fmt, ap);
212     fprintf(stderr, "\n");
213     va_end(ap);
214   }
215 }
216
217
218 #ifdef _WIN32
219 static BOOL WINAPI
220 capture_cleanup(DWORD dwCtrlType)
221 {
222     /* CTRL_C_EVENT is sort of like SIGINT, CTRL_BREAK_EVENT is unique to
223        Windows, CTRL_CLOSE_EVENT is sort of like SIGHUP, CTRL_LOGOFF_EVENT
224        is also sort of like SIGHUP, and CTRL_SHUTDOWN_EVENT is sort of
225        like SIGTERM at least when the machine's shutting down.
226
227        For now, if we're running as a command rather than a capture child,
228        we handle all but CTRL_LOGOFF_EVENT as indications that we should
229        clean up and quit, just as we handle SIGINT, SIGHUP, and SIGTERM
230        in that way on UN*X.
231
232        If we're not running as a capture child, we might be running as
233        a service; ignore CTRL_LOGOFF_EVENT, so we keep running after the
234        user logs out.  (XXX - can we explicitly check whether we're
235        running as a service?) */
236
237     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
238         "Console: Control signal");
239     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
240         "Console: Control signal, CtrlType: %u", dwCtrlType);
241
242     /* Keep capture running if we're a service and a user logs off */
243     if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) {
244         capture_loop_stop();
245         return TRUE;
246     } else {
247         return FALSE;
248     }
249 }
250 #else
251 static void
252 capture_cleanup(int signum)
253 {
254     /* On UN*X, we cleanly shut down the capture on SIGINT, SIGHUP, and
255        SIGTERM.  We assume that if the user wanted it to keep running
256        after they logged out, they'd have nohupped it. */
257
258     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
259         "Console: Signal");
260     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
261         "Console: Signal, signal value: %u", signum);
262
263     capture_loop_stop();
264 }
265 #endif
266
267 void exit_main(int status)
268 {
269 #ifdef _WIN32
270   /* Shutdown windows sockets */
271   WSACleanup();
272
273   /* can be helpful for debugging */
274 #ifdef DEBUG_DUMPCAP
275   printf("Press any key\n");
276   _getch();
277 #endif
278
279 #endif /* _WIN32 */
280
281   exit(status);
282 }
283
284 #ifdef HAVE_LIBCAP
285 /*
286  * If we were linked with libcap (not libpcap), make sure we have
287  * CAP_NET_ADMIN and CAP_NET_RAW, then relinquish our permissions.
288  */
289
290 void
291 #if 0 /* Set to enable capability debugging */
292 print_caps(char *pfx) {
293     cap_t caps = cap_get_proc();
294     fprintf(stderr, "%s: EUID: %d  Capabilities: %s\n", pfx,
295             geteuid(), cap_to_text(caps, NULL));
296     cap_free(caps);
297 #else
298 print_caps(char *pfx _U_) {
299 #endif
300 }
301
302 void
303 relinquish_privs_except_capture(void)
304 {
305     /* CAP_NET_ADMIN: Promiscuous mode and a truckload of other
306      *                stuff we don't need (and shouldn't have).
307      * CAP_NET_RAW:   Packet capture (raw sockets).
308      */
309     cap_value_t cap_list[2] = { CAP_NET_ADMIN, CAP_NET_RAW };
310     cap_t caps = cap_init();
311     int cl_len = sizeof(cap_list) / sizeof(cap_value_t);
312
313     if (started_with_special_privs()) {
314         print_caps("Pre drop, pre set");
315         if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
316             perror("prctl()");
317         }
318
319         cap_set_flag(caps, CAP_PERMITTED,   cl_len, cap_list, CAP_SET);
320         cap_set_flag(caps, CAP_INHERITABLE, cl_len, cap_list, CAP_SET);
321
322         if (cap_set_proc(caps)) {
323             perror("capset()");
324         }
325         print_caps("Pre drop, post set");
326     }
327
328     relinquish_special_privs_perm();
329
330     print_caps("Post drop, pre set");
331     cap_set_flag(caps, CAP_EFFECTIVE,   cl_len, cap_list, CAP_SET);
332     if (cap_set_proc(caps)) {
333         perror("capset()");
334     }
335     print_caps("Post drop, post set");
336     cap_free(caps);
337 }
338 #endif /* HAVE_LIBCAP */
339
340
341 /* And now our feature presentation... [ fade to music ] */
342 int
343 main(int argc, char *argv[])
344 {
345   int                  opt;
346   extern char         *optarg;
347   gboolean             arg_error = FALSE;
348
349 #ifdef _WIN32
350   WSADATA              wsaData;
351 #endif  /* _WIN32 */
352 #ifndef _WIN32
353   struct sigaction action, oldaction;
354 #endif
355
356   gboolean             start_capture = TRUE;
357   gboolean             stats_known;
358   struct pcap_stat     stats;
359   GLogLevelFlags       log_flags;
360   gboolean             list_interfaces = FALSE;
361   gboolean             list_link_layer_types = FALSE;
362   gboolean             machine_readable = FALSE;
363   gboolean             print_statistics = FALSE;
364   int                  status, run_once_args = 0;
365
366 #define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z:"
367
368 #ifdef _WIN32
369 #define OPTSTRING_WIN32 "B:"
370 #else
371 #define OPTSTRING_WIN32 ""
372 #endif  /* _WIN32 */
373
374   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
375     OPTSTRING_INIT OPTSTRING_WIN32;
376
377 #ifdef _WIN32
378   /* Load wpcap if possible. Do this before collecting the run-time version information */
379   load_wpcap();
380
381   /* ... and also load the packet.dll from wpcap */
382   /* XXX - currently not required, may change later. */
383   /*wpcap_packet_load();*/
384
385   /* Start windows sockets */
386   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
387
388   /* Set handler for Ctrl+C key */
389   SetConsoleCtrlHandler(capture_cleanup, TRUE);
390 #else
391   /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
392      and exit. */
393   action.sa_handler = capture_cleanup;
394   action.sa_flags = 0;
395   sigemptyset(&action.sa_mask);
396   sigaction(SIGTERM, &action, NULL);
397   sigaction(SIGINT, &action, NULL);
398   sigaction(SIGHUP, NULL, &oldaction);
399   if (oldaction.sa_handler == SIG_DFL)
400     sigaction(SIGHUP, &action, NULL);
401 #endif  /* _WIN32 */
402
403 #ifdef HAVE_LIBCAP
404   get_credential_info();
405   relinquish_privs_except_capture();
406 #endif
407
408   /* the default_log_handler will use stdout, which makes trouble in */
409   /* capture child mode, as it uses stdout for it's sync_pipe */
410   /* so do the filtering in the console_log_handler and not here */
411   log_flags =
412                     G_LOG_LEVEL_ERROR|
413                     G_LOG_LEVEL_CRITICAL|
414                     G_LOG_LEVEL_WARNING|
415                     G_LOG_LEVEL_MESSAGE|
416                     G_LOG_LEVEL_INFO|
417                     G_LOG_LEVEL_DEBUG|
418                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
419
420   g_log_set_handler(NULL,
421                     log_flags,
422                     console_log_handler, NULL /* user_data */);
423   g_log_set_handler(LOG_DOMAIN_MAIN,
424                     log_flags,
425                     console_log_handler, NULL /* user_data */);
426   g_log_set_handler(LOG_DOMAIN_CAPTURE,
427                     log_flags,
428             console_log_handler, NULL /* user_data */);
429   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
430                     log_flags,
431             console_log_handler, NULL /* user_data */);
432
433   /* Set the initial values in the capture_opts. This might be overwritten
434      by the command line parameters. */
435   capture_opts_init(capture_opts, NULL);
436
437   /* Default to capturing the entire packet. */
438   capture_opts->snaplen             = WTAP_MAX_PACKET_SIZE;
439
440   /* We always save to a file - if no file was specified, we save to a
441      temporary file. */
442   capture_opts->saving_to_file      = TRUE;
443   capture_opts->has_ring_num_files  = TRUE;
444
445   /* Now get our args */
446   while ((opt = getopt(argc, argv, optstring)) != -1) {
447     switch (opt) {
448       case 'h':        /* Print help and exit */
449         print_usage(TRUE);
450         exit_main(0);
451         break;
452       case 'v':        /* Show version and exit */
453       {
454         GString             *comp_info_str;
455         GString             *runtime_info_str;
456         /* Assemble the compile-time version information string */
457         comp_info_str = g_string_new("Compiled ");
458         get_compiled_version_info(comp_info_str, NULL);
459
460         /* Assemble the run-time version information string */
461         runtime_info_str = g_string_new("Running ");
462         get_runtime_version_info(runtime_info_str, NULL);
463         show_version(comp_info_str, runtime_info_str);
464         g_string_free(comp_info_str, TRUE);
465         g_string_free(runtime_info_str, TRUE);
466         exit_main(0);
467         break;
468       }
469       /*** capture option specific ***/
470       case 'a':        /* autostop criteria */
471       case 'b':        /* Ringbuffer option */
472       case 'c':        /* Capture x packets */
473       case 'f':        /* capture filter */
474       case 'i':        /* Use interface x */
475       case 'p':        /* Don't capture in promiscuous mode */
476       case 's':        /* Set the snapshot (capture) length */
477       case 'w':        /* Write to capture file x */
478       case 'y':        /* Set the pcap data link type */
479 #ifdef _WIN32
480       case 'B':        /* Buffer size */
481 #endif /* _WIN32 */
482         status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
483         if(status != 0) {
484             exit_main(status);
485         }
486         break;
487       /*** hidden option: Wireshark child mode (using binary output messages) ***/
488       case 'Z':
489           capture_child = TRUE;
490 #ifdef _WIN32
491           /* set output pipe to binary mode, to avoid ugly text conversions */
492           _setmode(2, O_BINARY);
493           /*
494            * optarg = the control ID, aka the PPID, currently used for the
495            * signal pipe name.
496            */
497           if (strcmp(optarg, SIGNAL_PIPE_CTRL_ID_NONE) != 0) {
498               sig_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT,
499                   optarg);
500               sig_pipe_handle = CreateFile(utf_8to16(sig_pipe_name),
501                   GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
502
503               if (sig_pipe_handle == INVALID_HANDLE_VALUE) {
504                   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
505                       "Signal pipe: Unable to open %s.  Dead parent?",
506                       sig_pipe_name);
507                   exit_main(1);
508               }
509           }
510 #endif
511           break;
512
513       /*** all non capture option specific ***/
514       case 'D':        /* Print a list of capture devices and exit */
515         list_interfaces = TRUE;
516         run_once_args++;
517         break;
518       case 'L':        /* Print list of link-layer types and exit */
519         list_link_layer_types = TRUE;
520         run_once_args++;
521         break;
522       case 'S':        /* Print interface statistics once a second */
523         print_statistics = TRUE;
524         run_once_args++;
525         break;
526       case 'M':        /* For -D and -L, print machine-readable output */
527         machine_readable = TRUE;
528         break;
529       default:
530       case '?':        /* Bad flag - print usage message */
531         cmdarg_err("Invalid Option: %s", argv[optind-1]);
532         arg_error = TRUE;
533         break;
534     }
535   }
536   argc -= optind;
537   argv += optind;
538   if (argc >= 1) {
539       /* user specified file name as regular command-line argument */
540       /* XXX - use it as the capture file name (or something else)? */
541     argc--;
542     argv++;
543   }
544
545   if (argc != 0) {
546     /*
547      * Extra command line arguments were specified; complain.
548      * XXX - interpret as capture filter, as tcpdump and tshark do?
549      */
550     cmdarg_err("Invalid argument: %s", argv[0]);
551     arg_error = TRUE;
552   }
553
554   if (arg_error) {
555     print_usage(FALSE);
556     exit_main(1);
557   }
558
559   if (run_once_args > 1) {
560     cmdarg_err("Only one of -D, -L, or -S may be supplied.");
561     exit_main(1);
562   } else if (list_link_layer_types) {
563     /* We're supposed to list the link-layer types for an interface;
564        did the user also specify a capture file to be read? */
565     /* No - did they specify a ring buffer option? */
566     if (capture_opts->multi_files_on) {
567       cmdarg_err("Ring buffer requested, but a capture isn't being done.");
568       exit_main(1);
569     }
570   } else {
571     /* No - was the ring buffer option specified and, if so, does it make
572        sense? */
573     if (capture_opts->multi_files_on) {
574       /* Ring buffer works only under certain conditions:
575          a) ring buffer does not work with temporary files;
576          b) it makes no sense to enable the ring buffer if the maximum
577             file size is set to "infinite". */
578       if (capture_opts->save_file == NULL) {
579         cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
580         capture_opts->multi_files_on = FALSE;
581       }
582       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
583         cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
584 /* XXX - this must be redesigned as the conditions changed */
585 /*      capture_opts->multi_files_on = FALSE;*/
586       }
587     }
588   }
589
590   if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
591         cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
592     exit_main(1);
593   }
594
595   /* Let the user know what interface was chosen. */
596   /* get_interface_descriptive_name() is not available! */
597   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", capture_opts->iface);
598
599   if (list_interfaces) {
600     status = capture_opts_list_interfaces(machine_readable);
601     exit_main(status);
602   } else if (list_link_layer_types) {
603     status = capture_opts_list_link_layer_types(capture_opts, machine_readable);
604     exit_main(status);
605   } else if (print_statistics) {
606     status = capture_opts_print_statistics(machine_readable);
607     exit_main(status);
608   }
609
610   capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
611   capture_opts_trim_ring_num_files(capture_opts);
612
613   /* Now start the capture. */
614
615   if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
616       /* capture ok */
617       exit_main(0);
618   } else {
619       /* capture failed */
620       exit_main(1);
621   }
622 }
623
624
625 static void
626 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
627                     const char *message, gpointer user_data _U_)
628 {
629   time_t curr;
630   struct tm *today;
631   const char *level;
632
633
634   /* ignore log message, if log_level isn't interesting */
635   if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
636 #ifndef DEBUG_DUMPCAP
637     return;
638 #endif
639   }
640
641   /* create a "timestamp" */
642   time(&curr);
643   today = localtime(&curr);
644
645   switch(log_level & G_LOG_LEVEL_MASK) {
646   case G_LOG_LEVEL_ERROR:
647     level = "Err ";
648     break;
649   case G_LOG_LEVEL_CRITICAL:
650     level = "Crit";
651     break;
652   case G_LOG_LEVEL_WARNING:
653     level = "Warn";
654     break;
655   case G_LOG_LEVEL_MESSAGE:
656     level = "Msg ";
657     break;
658   case G_LOG_LEVEL_INFO:
659     level = "Info";
660     break;
661   case G_LOG_LEVEL_DEBUG:
662     level = "Dbg ";
663     break;
664   default:
665     fprintf(stderr, "unknown log_level %u\n", log_level);
666     level = NULL;
667     g_assert_not_reached();
668   }
669
670   /* don't use printf (stdout), in child mode we're using stdout for the sync_pipe */
671   if(log_level & G_LOG_LEVEL_MESSAGE) {
672     /* normal user messages without additional infos */
673     fprintf(stderr, "%s\n", message);
674     fflush(stderr);
675   } else {
676     /* info/debug messages with additional infos */
677     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
678             today->tm_hour, today->tm_min, today->tm_sec,
679             log_domain != NULL ? log_domain : "",
680             level, message);
681     fflush(stderr);
682   }
683 }
684
685
686 /****************************************************************************************************************/
687 /* indication report routines */
688
689
690 void
691 report_packet_count(int packet_count)
692 {
693     char tmp[SP_DECISIZE+1+1];
694     static int count = 0;
695
696     if(capture_child) {
697         g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
698         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
699         pipe_write_block(2, SP_PACKET_COUNT, tmp);
700     } else {
701         count += packet_count;
702         fprintf(stderr, "\rPackets: %u ", count);
703         /* stderr could be line buffered */
704         fflush(stderr);
705     }
706 }
707
708 void
709 report_new_capture_file(const char *filename)
710 {
711     if(capture_child) {
712         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
713         pipe_write_block(2, SP_FILE, filename);
714     } else {
715         fprintf(stderr, "File: %s\n", filename);
716         /* stderr could be line buffered */
717         fflush(stderr);
718     }
719 }
720
721 void
722 report_cfilter_error(const char *cfilter, const char *errmsg)
723 {
724     if (capture_child) {
725         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg);
726         pipe_write_block(2, SP_BAD_FILTER, errmsg);
727     } else {
728         fprintf(stderr,
729           "Invalid capture filter: \"%s\"!\n"
730           "\n"
731           "That string isn't a valid capture filter (%s).\n"
732           "See the User's Guide for a description of the capture filter syntax.\n",
733           cfilter, errmsg);
734     }
735 }
736
737 void
738 report_capture_error(const char *error_msg, const char *secondary_error_msg)
739 {
740     if(capture_child) {
741         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
742             "Primary Error: %s", error_msg);
743         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
744             "Secondary Error: %s", secondary_error_msg);
745         sync_pipe_errmsg_to_parent(2, error_msg, secondary_error_msg);
746     } else {
747         fprintf(stderr, "%s\n%s\n", error_msg, secondary_error_msg);
748     }
749 }
750
751 void
752 report_packet_drops(int drops)
753 {
754     char tmp[SP_DECISIZE+1+1];
755
756     g_snprintf(tmp, sizeof(tmp), "%d", drops);
757
758     if(capture_child) {
759         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets dropped: %s", tmp);
760         pipe_write_block(2, SP_DROPS, tmp);
761     } else {
762         fprintf(stderr, "Packets dropped: %s\n", tmp);
763         /* stderr could be line buffered */
764         fflush(stderr);
765     }
766 }
767
768
769 /****************************************************************************************************************/
770 /* signal_pipe handling */
771
772
773 #ifdef _WIN32
774 gboolean
775 signal_pipe_check_running(void)
776 {
777     /* any news from our parent? -> just stop the capture */
778     DWORD avail = 0;
779     gboolean result;
780
781     /* if we are running standalone, no check required */
782     if(!capture_child) {
783         return TRUE;
784     }
785
786     if(!sig_pipe_name || !sig_pipe_handle) {
787         /* This shouldn't happen */
788         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
789             "Signal pipe: No name or handle");
790         return FALSE;
791     }
792
793     /*
794      * XXX - We should have the process ID of the parent (from the "-Z" flag)
795      * at this point.  Should we check to see if the parent is still alive,
796      * e.g. by using OpenProcess?
797      */
798
799     result = PeekNamedPipe(sig_pipe_handle, NULL, 0, NULL, &avail, NULL);
800
801     if(!result || avail > 0) {
802         /* peek failed or some bytes really available */
803         /* (if not piping from stdin this would fail) */
804         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
805             "Signal pipe: Stop capture: %s", sig_pipe_name);
806         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
807             "Signal pipe: %s (%p) result: %u avail: %u", sig_pipe_name,
808             sig_pipe_handle, result, avail);
809         return FALSE;
810     } else {
811         /* pipe ok and no bytes available */
812         return TRUE;
813     }
814 }
815 #endif