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