+#if USE_NCURSES
+ update_stats_from_context (context, iter);
+ wrefresh (main_win);
+#endif
+} /* }}} void update_host_hook */
+
+/* Prints statistics for each host, cleans up the contexts and returns the
+ * number of hosts which failed to return more than the fraction
+ * opt_exit_status_threshold of pings. */
+static int post_loop_hook (pingobj_t *ping) /* {{{ */
+{
+ pingobj_iter_t *iter;
+ int failure_count = 0;
+
+#if USE_NCURSES
+ endwin ();
+#endif
+
+ for (iter = ping_iterator_get (ping);
+ iter != NULL;
+ iter = ping_iterator_next (iter))
+ {
+ ping_context_t *context;
+
+ context = ping_iterator_get_context (iter);
+
+ printf ("\n--- %s ping statistics ---\n"
+ "%i packets transmitted, %i received, %.2f%% packet loss, time %.1fms\n",
+ context->host, context->req_sent, context->req_rcvd,
+ context_get_packet_loss (context),
+ context->latency_total);
+
+ {
+ double pct_failed = 1.0 - (((double) context->req_rcvd)
+ / ((double) context->req_sent));
+ if (pct_failed > opt_exit_status_threshold)
+ failure_count++;
+ }
+
+ if (context->req_rcvd != 0)
+ {
+ double average;
+ double deviation;
+ double percentile;
+
+ average = context_get_average (context);
+ deviation = context_get_stddev (context);
+ percentile = context_get_percentile (context, opt_percentile);
+
+ printf ("rtt min/avg/%.0f%%/max/sdev = "
+ "%.3f/%.3f/%.0f/%.3f/%.3f ms\n",
+ opt_percentile,
+ context->latency_min,
+ average,
+ percentile,
+ context->latency_max,
+ deviation);
+ }
+
+ ping_iterator_set_context (iter, NULL);
+ context_destroy (context);
+ }
+
+ return (failure_count);
+} /* }}} int post_loop_hook */
+
+int main (int argc, char **argv) /* {{{ */
+{
+ pingobj_t *ping;
+ pingobj_iter_t *iter;
+
+ struct sigaction sigint_action;
+
+ struct timeval tv_begin;
+ struct timeval tv_end;
+ struct timespec ts_wait;
+ struct timespec ts_int;
+
+ int optind;
+ int i;
+ int status;
+#if _POSIX_SAVED_IDS
+ uid_t saved_set_uid;
+
+ /* Save the old effective user id */
+ saved_set_uid = geteuid ();
+ /* Set the effective user ID to the real user ID without changing the
+ * saved set-user ID */
+ status = seteuid (getuid ());
+ if (status != 0)
+ {
+ fprintf (stderr, "Temporarily dropping privileges "
+ "failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ setlocale(LC_ALL, "");
+ optind = read_options (argc, argv);
+
+#if !_POSIX_SAVED_IDS
+ /* Cannot temporarily drop privileges -> reject every file but "-". */
+ if ((opt_filename != NULL)
+ && (strcmp ("-", opt_filename) != 0)
+ && (getuid () != geteuid ()))
+ {
+ fprintf (stderr, "Your real and effective user IDs don't "
+ "match. Reading from a file (option '-f')\n"
+ "is therefore too risky. You can still read "
+ "from STDIN using '-f -' if you like.\n"
+ "Sorry.\n");
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ if ((optind >= argc) && (opt_filename == NULL)) {
+ usage_exit (argv[0], 1);
+ }
+
+ if ((ping = ping_construct ()) == NULL)
+ {
+ fprintf (stderr, "ping_construct failed\n");
+ return (1);
+ }
+
+ if (ping_setopt (ping, PING_OPT_TTL, &opt_send_ttl) != 0)
+ {
+ fprintf (stderr, "Setting TTL to %i failed: %s\n",
+ opt_send_ttl, ping_get_error (ping));
+ }
+
+ if (ping_setopt (ping, PING_OPT_QOS, &opt_send_qos) != 0)
+ {
+ fprintf (stderr, "Setting TOS to %i failed: %s\n",
+ opt_send_qos, ping_get_error (ping));
+ }
+
+ {
+ double temp_sec;
+ double temp_nsec;
+
+ temp_nsec = modf (opt_interval, &temp_sec);
+ ts_int.tv_sec = (time_t) temp_sec;
+ ts_int.tv_nsec = (long) (temp_nsec * 1000000000L);
+
+ /* printf ("ts_int = %i.%09li\n", (int) ts_int.tv_sec, ts_int.tv_nsec); */
+ }
+
+ if (opt_addrfamily != PING_DEF_AF)
+ ping_setopt (ping, PING_OPT_AF, (void *) &opt_addrfamily);
+
+ if (opt_srcaddr != NULL)
+ {
+ if (ping_setopt (ping, PING_OPT_SOURCE, (void *) opt_srcaddr) != 0)
+ {
+ fprintf (stderr, "Setting source address failed: %s\n",
+ ping_get_error (ping));
+ }
+ }
+
+ if (opt_device != NULL)
+ {
+ if (ping_setopt (ping, PING_OPT_DEVICE, (void *) opt_device) != 0)
+ {
+ fprintf (stderr, "Setting device failed: %s\n",
+ ping_get_error (ping));
+ }
+ }
+
+ if (opt_filename != NULL)
+ {
+ FILE *infile;
+ char line[256];
+ char host[256];
+
+ if (strcmp (opt_filename, "-") == 0)
+ /* Open STDIN */
+ infile = fdopen(0, "r");
+ else
+ infile = fopen(opt_filename, "r");
+
+ if (infile == NULL)
+ {
+ fprintf (stderr, "Opening %s failed: %s\n",
+ (strcmp (opt_filename, "-") == 0)
+ ? "STDIN" : opt_filename,
+ strerror(errno));
+ return (1);
+ }
+
+#if _POSIX_SAVED_IDS
+ /* Regain privileges */
+ status = seteuid (saved_set_uid);
+ if (status != 0)
+ {
+ fprintf (stderr, "Temporarily re-gaining privileges "
+ "failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ while (fgets(line, sizeof(line), infile))
+ {
+ /* Strip whitespace */
+ if (sscanf(line, "%s", host) != 1)
+ continue;
+
+ if ((host[0] == 0) || (host[0] == '#'))
+ continue;
+
+ if (ping_host_add(ping, host) < 0)
+ {
+ const char *errmsg = ping_get_error (ping);
+
+ fprintf (stderr, "Adding host `%s' failed: %s\n", host, errmsg);
+ continue;
+ }
+ else
+ {
+ host_num++;
+ }
+ }
+
+#if _POSIX_SAVED_IDS
+ /* Drop privileges */
+ status = seteuid (getuid ());
+ if (status != 0)
+ {
+ fprintf (stderr, "Temporarily dropping privileges "
+ "failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ fclose(infile);
+ }
+
+#if _POSIX_SAVED_IDS
+ /* Regain privileges */
+ status = seteuid (saved_set_uid);
+ if (status != 0)
+ {
+ fprintf (stderr, "Temporarily re-gaining privileges "
+ "failed: %s\n", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ for (i = optind; i < argc; i++)
+ {
+ if (ping_host_add (ping, argv[i]) < 0)
+ {
+ const char *errmsg = ping_get_error (ping);
+
+ fprintf (stderr, "Adding host `%s' failed: %s\n", argv[i], errmsg);
+ continue;
+ }
+ else
+ {
+ host_num++;
+ }
+ }
+
+ /* Permanently drop root privileges if we're setuid-root. */
+ status = setuid (getuid ());
+ if (status != 0)
+ {
+ fprintf (stderr, "Dropping privileges failed: %s\n",
+ strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+
+#if _POSIX_SAVED_IDS
+ saved_set_uid = (uid_t) -1;
+#endif
+
+ ping_initialize_contexts (ping);
+