Start of functional client

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/client.c b/client.c
index c94ccf3..6aaad01 100644
--- a/client.c
+++ b/client.c
@@ -70,9 +70,6 @@
 
 	fio_net_cmd_crc(cmd);
 
-	printf("cmd crc %x, pdu crc %x\n", cmd->cmd_crc32, cmd->pdu_crc32);
-	printf("job %x\n", cmd->opcode);
-
 	ret = fio_send_data(fio_client_fd, cmd, sizeof(*cmd) + size);
 	free(cmd);
 	return ret;
@@ -122,3 +119,27 @@
 	free(buf);
 	return ret;
 }
+
+int fio_handle_clients(void)
+{
+	struct fio_net_cmd *cmd;
+
+	while (!exit_backend) {
+		cmd = fio_net_cmd_read(fio_client_fd);
+
+		if (cmd->opcode == FIO_NET_CMD_ACK) {
+			free(cmd);
+			continue;
+		}
+		if (cmd->opcode != FIO_NET_CMD_TEXT) {
+			printf("non text: %d\n", cmd->opcode);
+			free(cmd);
+			continue;
+		}
+		printf("%s", cmd->payload);
+		fflush(stdout);
+		free(cmd);
+	}
+
+	return 0;
+}
diff --git a/eta.c b/eta.c
index d93bf1a..fc0292f 100644
--- a/eta.c
+++ b/eta.c
@@ -249,6 +249,7 @@
 	static unsigned int rate[2], iops[2];
 	static int linelen_last;
 	static int eta_good;
+	char output[512], *p = output;
 	int i2p = 0;
 
 	if (temp_stall_ts || terse_output || eta_print == FIO_ETA_NEVER)
@@ -355,17 +356,17 @@
 	if (!nr_running && !nr_pending)
 		return;
 
-	printf("Jobs: %d (f=%d)", nr_running, files_open);
+	p += sprintf(p, "Jobs: %d (f=%d)", nr_running, files_open);
 	if (m_rate || t_rate) {
 		char *tr, *mr;
 
 		mr = num2str(m_rate, 4, 0, i2p);
 		tr = num2str(t_rate, 4, 0, i2p);
-		printf(", CR=%s/%s KB/s", tr, mr);
+		p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
 		free(tr);
 		free(mr);
 	} else if (m_iops || t_iops)
-		printf(", CR=%d/%d IOPS", t_iops, m_iops);
+		p += sprintf(p, ", CR=%d/%d IOPS", t_iops, m_iops);
 	if (eta_sec != INT_MAX && nr_running) {
 		char perc_str[32];
 		char *iops_str[2];
@@ -386,11 +387,12 @@
 		iops_str[0] = num2str(iops[0], 4, 1, 0);
 		iops_str[1] = num2str(iops[1], 4, 1, 0);
 
-		l = printf(": [%s] [%s] [%s/%s /s] [%s/%s iops] [eta %s]",
+		l = sprintf(p, ": [%s] [%s] [%s/%s /s] [%s/%s iops] [eta %s]",
 				 run_str, perc_str, rate_str[0], rate_str[1],
 				 iops_str[0], iops_str[1], eta_str);
+		p += l;
 		if (l >= 0 && l < linelen_last)
-			printf("%*s", linelen_last - l, "");
+			p += sprintf(p, "%*s", linelen_last - l, "");
 		linelen_last = l;
 
 		free(rate_str[0]);
@@ -398,8 +400,13 @@
 		free(iops_str[0]);
 		free(iops_str[1]);
 	}
-	printf("\r");
-	fflush(stdout);
+	p += sprintf(p, "\r");
+
+	if (!is_backend) {
+		printf("%s", output);
+		fflush(stdout);
+	} else
+		fio_server_text_output(output, p - output);
 }
 
 void print_status_init(int thr_number)
diff --git a/fio.c b/fio.c
index a15080b..bd566e8 100644
--- a/fio.c
+++ b/fio.c
@@ -139,9 +139,7 @@
 		if (!threads)
 			break;
 		update_io_ticks();
-
-		if (!is_backend)
-			print_thread_status();
+		print_thread_status();
 	}
 
 	return NULL;
@@ -1696,6 +1694,8 @@
 
 int exec_run(void)
 {
+	if (is_client)
+		return fio_handle_clients();
 	if (exec_profile && load_profile(exec_profile))
 		return 1;
 
diff --git a/fio.h b/fio.h
index d36ee16..e46a1a3 100644
--- a/fio.h
+++ b/fio.h
@@ -35,6 +35,7 @@
 #include "time.h"
 #include "lib/getopt.h"
 #include "lib/rand.h"
+#include "server.h"
 
 #ifdef FIO_HAVE_GUASI
 #include <guasi.h>
@@ -651,6 +652,7 @@
 extern int warnings_fatal;
 extern int terse_version;
 extern int is_backend;
+extern int is_client;
 
 extern struct thread_data *threads;
 
diff --git a/init.c b/init.c
index 088e814..28852fb 100644
--- a/init.c
+++ b/init.c
@@ -1412,7 +1412,7 @@
 			return 0;
 		if (exec_profile)
 			return 0;
-		if (is_backend)
+		if (is_backend || is_client)
 			return 0;
 
 		log_err("No jobs(s) defined\n\n");
diff --git a/server.c b/server.c
index f393873..1749e73 100644
--- a/server.c
+++ b/server.c
@@ -24,6 +24,8 @@
 static unsigned int job_cur_len;
 static unsigned int job_max_len;
 
+static int server_fd;
+
 int fio_send_data(int sk, const void *p, unsigned int len)
 {
 	do {
@@ -106,7 +108,7 @@
 	return 0;
 }
 
-static struct fio_net_cmd *read_command(int sk)
+struct fio_net_cmd *fio_net_cmd_read(int sk)
 {
 	struct fio_net_cmd cmd, *ret = NULL;
 	uint32_t crc;
@@ -242,7 +244,7 @@
 
 	/* read forever */
 	while (!exit_backend) {
-		cmd = read_command(sk);
+		cmd = fio_net_cmd_read(sk);
 		if (!cmd) {
 			ret = 1;
 			break;
@@ -301,8 +303,11 @@
 		return -1;
 	}
 
+	server_fd = sk;
+
 	exitval = handle_connection(sk);
 
+	server_fd = -1;
 	close(sk);
 
 	if (!exit_backend)
@@ -361,3 +366,19 @@
 	close(sk);
 	return ret;
 }
+
+void fio_server_text_output(const char *buf, unsigned int len)
+{
+	struct fio_net_cmd *cmd;
+
+	cmd = malloc(sizeof(*cmd) + len);
+	fio_init_net_cmd(cmd);
+	cmd->opcode	= cpu_to_le16(FIO_NET_CMD_TEXT);
+	cmd->pdu_len	= cpu_to_le32(len);
+	memcpy(&cmd->payload, buf, len);
+
+	fio_net_cmd_crc(cmd);
+
+	fio_send_data(server_fd, cmd, sizeof(*cmd) + len);
+	free(cmd);
+}
diff --git a/server.h b/server.h
index 51a8417..c2cb994 100644
--- a/server.h
+++ b/server.h
@@ -30,16 +30,20 @@
 	FIO_NET_CMD_JOB_END	= 3,
 	FIO_NET_CMD_ACK		= 4,
 	FIO_NET_CMD_NAK		= 5,
+	FIO_NET_CMD_TEXT	= 6,
 };
 
 extern int fio_server(void);
+extern void fio_server_text_output(const char *, unsigned int len);
 
 extern int fio_client_connect(const char *);
 extern int fio_client_send_ini(const char *);
+extern int fio_handle_clients(void);
 
 extern int fio_recv_data(int sk, void *p, unsigned int len);
 extern int fio_send_data(int sk, const void *p, unsigned int len);
 extern void fio_net_cmd_crc(struct fio_net_cmd *);
+extern struct fio_net_cmd *fio_net_cmd_read(int sk);
 
 extern int exit_backend;
 extern int fio_net_port;