Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 0aa70f423d0b7162d509dad82025424772c65808)
+++ uspace/app/ping/ping.c	(revision dd7078cd83b34210e136db268a0c0f11fdf70e7c)
@@ -42,6 +42,9 @@
 #include <inet/inetping.h>
 #include <io/console.h>
+#include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
 #include <sys/types.h>
 
@@ -54,9 +57,19 @@
 #define PING_TIMEOUT (1000 * 1000)
 
+typedef enum {
+	RECEIVED_NONE,
+	RECEIVED_SUCCESS,
+	RECEIVED_INTERRUPT
+} received_t;
+
+static received_t received;
+static FIBRIL_CONDVAR_INITIALIZE(received_cv);
+static FIBRIL_MUTEX_INITIALIZE(received_lock);
+
+static bool quit = false;
+static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
+static FIBRIL_MUTEX_INITIALIZE(quit_lock);
+
 static int ping_ev_recv(inetping_sdu_t *);
-
-static bool done = false;
-static FIBRIL_CONDVAR_INITIALIZE(done_cv);
-static FIBRIL_MUTEX_INITIALIZE(done_lock);
 
 static inetping_ev_ops_t ev_ops = {
@@ -67,17 +80,28 @@
 static addr32_t dest;
 
-static bool ping_repeat = false;
+static bool repeat_forever = false;
+static size_t repeat_count = 1;
+
+static const char *short_options = "rn:";
 
 static void print_syntax(void)
 {
-	printf("syntax: " NAME " [-r] <host>\n");
-}
-
-static void ping_signal_done(void)
-{
-	fibril_mutex_lock(&done_lock);
-	done = true;
-	fibril_mutex_unlock(&done_lock);
-	fibril_condvar_broadcast(&done_cv);
+	printf("Syntax: %s [-n <count>|-r] <host>\n", NAME);
+}
+
+static void ping_signal_received(received_t value)
+{
+	fibril_mutex_lock(&received_lock);
+	received = value;
+	fibril_mutex_unlock(&received_lock);
+	fibril_condvar_broadcast(&received_cv);
+}
+
+static void ping_signal_quit(void)
+{
+	fibril_mutex_lock(&quit_lock);
+	quit = true;
+	fibril_mutex_unlock(&quit_lock);
+	fibril_condvar_broadcast(&quit_cv);
 }
 
@@ -105,6 +129,5 @@
 	    "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
 	
-	if (!ping_repeat)
-		ping_signal_done();
+	ping_signal_received(RECEIVED_SUCCESS);
 	
 	free(asrc);
@@ -116,6 +139,5 @@
 {
 	inetping_sdu_t sdu;
-	int rc;
-
+	
 	sdu.src = src;
 	sdu.dest = dest;
@@ -123,12 +145,11 @@
 	sdu.data = (void *) "foo";
 	sdu.size = 3;
-
-	rc = inetping_send(&sdu);
-	if (rc != EOK) {
-		printf(NAME ": Failed sending echo request (%d).\n", rc);
-		return rc;
-	}
-
-	return EOK;
+	
+	int rc = inetping_send(&sdu);
+	if (rc != EOK)
+		printf("Failed sending echo request: %s (%d).\n",
+		    str_error(rc), rc);
+	
+	return rc;
 }
 
@@ -136,43 +157,60 @@
 {
 	uint16_t seq_no = 0;
-
+	
+	while ((repeat_count--) || (repeat_forever)) {
+		fibril_mutex_lock(&received_lock);
+		received = RECEIVED_NONE;
+		fibril_mutex_unlock(&received_lock);
+		
+		(void) ping_send(++seq_no);
+		
+		fibril_mutex_lock(&received_lock);
+		int rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
+		    PING_TIMEOUT);
+		received_t recv = received;
+		fibril_mutex_unlock(&received_lock);
+		
+		if ((rc == ETIMEOUT) || (recv == RECEIVED_NONE))
+			printf("Echo request timed out (seq. no %u)\n", seq_no);
+		
+		if (recv == RECEIVED_INTERRUPT)
+			break;
+		
+		if ((repeat_count > 0) || (repeat_forever)) {
+			fibril_mutex_lock(&received_lock);
+			rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
+			    PING_DELAY);
+			recv = received;
+			fibril_mutex_unlock(&received_lock);
+			
+			if (recv == RECEIVED_INTERRUPT)
+				break;
+		}
+	}
+	
+	ping_signal_quit();
+	return 0;
+}
+
+static int input_fibril(void *arg)
+{
+	console_ctrl_t *con = console_init(stdin, stdout);
+	
 	while (true) {
-		fibril_mutex_lock(&done_lock);
-		if (done) {
-			fibril_mutex_unlock(&done_lock);
-			return 0;
-		}
-		fibril_mutex_unlock(&done_lock);
-
-		(void) ping_send(++seq_no);
-		async_usleep(PING_DELAY);
-	}
-
-	return 0;
-}
-
-static int input_fibril(void *arg)
-{
-	console_ctrl_t *con;
-	cons_event_t ev;
-
-	con = console_init(stdin, stdout);
-	printf("[Press Ctrl-Q to quit]\n");
-
-	while (true) {
+		cons_event_t ev;
 		if (!console_get_event(con, &ev))
 			break;
-
-		if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS &&
-		    (ev.ev.key.mods & (KM_ALT | KM_SHIFT)) ==
-		    0 && (ev.ev.key.mods & KM_CTRL) != 0) {
+		
+		if ((ev.type == CEV_KEY) && (ev.ev.key.type == KEY_PRESS) &&
+		    ((ev.ev.key.mods & (KM_ALT | KM_SHIFT)) == 0) &&
+		    ((ev.ev.key.mods & KM_CTRL) != 0)) {
 			/* Ctrl+key */
 			if (ev.ev.key.key == KC_Q) {
-				ping_signal_done();
-				return 0;
+				ping_signal_received(RECEIVED_INTERRUPT);
+				break;
 			}
 		}
 	}
-
+	
 	return 0;
 }
@@ -184,35 +222,47 @@
 	char *adest = NULL;
 	char *sdest = NULL;
-	int rc;
-	int argi;
-
-	rc = inetping_init(&ev_ops);
-	if (rc != EOK) {
-		printf(NAME ": Failed connecting to internet ping service "
-		    "(%d).\n", rc);
-		goto error;
-	}
-
-	argi = 1;
-	if (argi < argc && str_cmp(argv[argi], "-r") == 0) {
-		ping_repeat = true;
-		++argi;
-	} else {
-		ping_repeat = false;
-	}
-
-	if (argc - argi != 1) {
+	
+	int rc = inetping_init(&ev_ops);
+	if (rc != EOK) {
+		printf("Failed connecting to internet ping service: "
+		    "%s (%d).\n", str_error(rc), rc);
+		goto error;
+	}
+	
+	int c;
+	while ((c = getopt(argc, argv, short_options)) != -1) {
+		switch (c) {
+		case 'r':
+			repeat_forever = true;
+			break;
+		case 'n':
+			rc = str_size_t(optarg, NULL, 10, true, &repeat_count);
+			if (rc != EOK) {
+				printf("Invalid repeat count.\n");
+				print_syntax();
+				goto error;
+			}
+			break;
+		default:
+			printf("Unknown option passed.\n");
+			print_syntax();
+			goto error;
+		}
+	}
+	
+	if (optind >= argc) {
+		printf("IP address or host name not supplied.\n");
 		print_syntax();
 		goto error;
 	}
-
+	
 	/* Parse destination address */
 	inet_addr_t dest_addr;
-	rc = inet_addr_parse(argv[argi], &dest_addr);
+	rc = inet_addr_parse(argv[optind], &dest_addr);
 	if (rc != EOK) {
 		/* Try interpreting as a host name */
-		rc = dnsr_name2host(argv[argi], &hinfo, AF_INET);
+		rc = dnsr_name2host(argv[optind], &hinfo, AF_INET);
 		if (rc != EOK) {
-			printf(NAME ": Error resolving host '%s'.\n", argv[argi]);
+			printf("Error resolving host '%s'.\n", argv[optind]);
 			goto error;
 		}
@@ -223,6 +273,6 @@
 	uint16_t af = inet_addr_get(&dest_addr, &dest, NULL);
 	if (af != AF_INET) {
-		printf(NAME ": Destination '%s' is not an IPv4 address.\n",
-		    argv[argi]);
+		printf("Destination '%s' is not an IPv4 address.\n",
+		    argv[optind]);
 		goto error;
 	}
@@ -231,5 +281,5 @@
 	rc = inetping_get_srcaddr(dest, &src);
 	if (rc != EOK) {
-		printf(NAME ": Failed determining source address.\n");
+		printf("Failed determining source address.\n");
 		goto error;
 	}
@@ -240,5 +290,5 @@
 	rc = inet_addr_format(&src_addr, &asrc);
 	if (rc != EOK) {
-		printf(NAME ": Out of memory.\n");
+		printf("Out of memory.\n");
 		goto error;
 	}
@@ -246,5 +296,5 @@
 	rc = inet_addr_format(&dest_addr, &adest);
 	if (rc != EOK) {
-		printf(NAME ": Out of memory.\n");
+		printf("Out of memory.\n");
 		goto error;
 	}
@@ -253,5 +303,5 @@
 		rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
 		if (rc < 0) {
-			printf(NAME ": Out of memory.\n");
+			printf("Out of memory.\n");
 			goto error;
 		}
@@ -260,43 +310,29 @@
 		adest = NULL;
 	}
-
-	printf("Sending ICMP echo request from %s to %s.\n",
+	
+	printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
 	    asrc, sdest);
-
-	fid_t fid;
-
-	if (ping_repeat) {
-		fid = fibril_create(transmit_fibril, NULL);
-		if (fid == 0) {
-			printf(NAME ": Failed creating transmit fibril.\n");
-			goto error;
-		}
-
-		fibril_add_ready(fid);
-
-		fid = fibril_create(input_fibril, NULL);
-		if (fid == 0) {
-			printf(NAME ": Failed creating input fibril.\n");
-			goto error;
-		}
-
-		fibril_add_ready(fid);
-	} else {
-		ping_send(1);
-	}
-
-	fibril_mutex_lock(&done_lock);
-	rc = EOK;
-	while (!done && rc != ETIMEOUT) {
-		rc = fibril_condvar_wait_timeout(&done_cv, &done_lock,
-			ping_repeat ? 0 : PING_TIMEOUT);
-	}
-	fibril_mutex_unlock(&done_lock);
-
-	if (rc == ETIMEOUT) {
-		printf(NAME ": Echo request timed out.\n");
-		goto error;
-	}
-
+	
+	fid_t fid = fibril_create(transmit_fibril, NULL);
+	if (fid == 0) {
+		printf("Failed creating transmit fibril.\n");
+		goto error;
+	}
+	
+	fibril_add_ready(fid);
+	
+	fid = fibril_create(input_fibril, NULL);
+	if (fid == 0) {
+		printf("Failed creating input fibril.\n");
+		goto error;
+	}
+	
+	fibril_add_ready(fid);
+	
+	fibril_mutex_lock(&quit_lock);
+	while (!quit)
+		fibril_condvar_wait(&quit_cv, &quit_lock);
+	fibril_mutex_unlock(&quit_lock);
+	
 	free(asrc);
 	free(adest);
