xref: /openbsd-src/usr.sbin/iscsictl/iscsictl.c (revision fcd5019890c71998da94d7a33da06e9da845e9b2)
1*fcd50198Smbuhl /*	$OpenBSD: iscsictl.c,v 1.13 2023/02/21 15:45:40 mbuhl Exp $ */
2208af722Sclaudio 
3208af722Sclaudio /*
4208af722Sclaudio  * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
5208af722Sclaudio  *
6208af722Sclaudio  * Permission to use, copy, modify, and distribute this software for any
7208af722Sclaudio  * purpose with or without fee is hereby granted, provided that the above
8208af722Sclaudio  * copyright notice and this permission notice appear in all copies.
9208af722Sclaudio  *
10208af722Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11208af722Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12208af722Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13208af722Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14208af722Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15208af722Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16208af722Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17208af722Sclaudio  */
18208af722Sclaudio 
19208af722Sclaudio #include <sys/queue.h>
20208af722Sclaudio #include <sys/socket.h>
21208af722Sclaudio #include <sys/uio.h>
22208af722Sclaudio #include <sys/un.h>
23208af722Sclaudio 
24208af722Sclaudio #include <event.h>
25208af722Sclaudio #include <err.h>
26208af722Sclaudio #include <errno.h>
27208af722Sclaudio #include <stdio.h>
28208af722Sclaudio #include <stdlib.h>
29208af722Sclaudio #include <string.h>
30208af722Sclaudio #include <unistd.h>
312fe39d32Sclaudio #include <util.h>
32208af722Sclaudio 
33208af722Sclaudio #include "iscsid.h"
34208af722Sclaudio #include "iscsictl.h"
35208af722Sclaudio 
36208af722Sclaudio __dead void	 usage(void);
37d9ff5473Sclaudio void		 run(void);
38d9ff5473Sclaudio void		 run_command(struct pdu *);
39208af722Sclaudio struct pdu	*ctl_getpdu(char *, size_t);
40208af722Sclaudio int		 ctl_sendpdu(int, struct pdu *);
41d9ff5473Sclaudio void		 show_config(struct ctrlmsghdr *, struct pdu *);
42cf4672e7Sclaudio void		 show_vscsi_stats(struct ctrlmsghdr *, struct pdu *);
432f8c4829Sclaudio void             poll_and_wait(void);
442f8c4829Sclaudio void             poll_session_status(void);
452f8c4829Sclaudio void             register_poll(struct ctrlmsghdr *, struct pdu *);
462f8c4829Sclaudio void             poll_print(struct session_poll *);
47208af722Sclaudio 
48208af722Sclaudio char		cbuf[CONTROL_READ_SIZE];
49208af722Sclaudio 
50d9ff5473Sclaudio struct control {
51d9ff5473Sclaudio 	struct pduq	channel;
52d9ff5473Sclaudio 	int		fd;
53d9ff5473Sclaudio } control;
54d9ff5473Sclaudio 
552f8c4829Sclaudio 
562f8c4829Sclaudio struct session_poll poll_result;
572f8c4829Sclaudio #define POLL_DELAY_SEC	1
582f8c4829Sclaudio #define POLL_ATTEMPTS	10
592f8c4829Sclaudio 
60208af722Sclaudio __dead void
usage(void)61208af722Sclaudio usage(void)
62208af722Sclaudio {
63208af722Sclaudio 	extern char *__progname;
64208af722Sclaudio 
65208af722Sclaudio 	fprintf(stderr,"usage: %s [-s socket] command [argument ...]\n",
66208af722Sclaudio 	    __progname);
67208af722Sclaudio 	exit(1);
68208af722Sclaudio }
69208af722Sclaudio 
70208af722Sclaudio int
main(int argc,char * argv[])71208af722Sclaudio main (int argc, char* argv[])
72208af722Sclaudio {
73208af722Sclaudio 	struct sockaddr_un sun;
74d9ff5473Sclaudio 	struct session_config sc;
75208af722Sclaudio 	struct parse_result *res;
76208af722Sclaudio 	char *confname = ISCSID_CONFIG;
77208af722Sclaudio 	char *sockname = ISCSID_CONTROL;
78208af722Sclaudio 	struct session_ctlcfg *s;
79208af722Sclaudio 	struct iscsi_config *cf;
802f8c4829Sclaudio 	int ch, poll = 0, val = 0;
81208af722Sclaudio 
82208af722Sclaudio 	/* check flags */
83208af722Sclaudio 	while ((ch = getopt(argc, argv, "f:s:")) != -1) {
84208af722Sclaudio 		switch (ch) {
85208af722Sclaudio 		case 'f':
86208af722Sclaudio 			confname = optarg;
87208af722Sclaudio 			break;
88208af722Sclaudio 		case 's':
89208af722Sclaudio 			sockname = optarg;
90208af722Sclaudio 			break;
91208af722Sclaudio 		default:
92208af722Sclaudio 			usage();
93208af722Sclaudio 			/* NOTREACHED */
94208af722Sclaudio 		}
95208af722Sclaudio 	}
96208af722Sclaudio 	argc -= optind;
97208af722Sclaudio 	argv += optind;
98208af722Sclaudio 
99208af722Sclaudio 	/* parse options */
100208af722Sclaudio 	if ((res = parse(argc, argv)) == NULL)
101208af722Sclaudio 		exit(1);
102208af722Sclaudio 
103761f0b52Sgsoares 	/* connect to iscsid control socket */
104d9ff5473Sclaudio 	TAILQ_INIT(&control.channel);
105d9ff5473Sclaudio 	if ((control.fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
106208af722Sclaudio 		err(1, "socket");
107208af722Sclaudio 
108208af722Sclaudio 	bzero(&sun, sizeof(sun));
109208af722Sclaudio 	sun.sun_family = AF_UNIX;
110208af722Sclaudio 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
111208af722Sclaudio 
112d9ff5473Sclaudio 	if (connect(control.fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
113208af722Sclaudio 		err(1, "connect: %s", sockname);
114208af722Sclaudio 
115ed720fabSderaadt 	if (pledge("stdio rpath dns", NULL) == -1)
116ed720fabSderaadt 		err(1, "pledge");
117ed720fabSderaadt 
118208af722Sclaudio 	switch (res->action) {
119208af722Sclaudio 	case NONE:
120208af722Sclaudio 	case LOG_VERBOSE:
1213471b912Sclaudio 		val = 1;
1223471b912Sclaudio 		/* FALLTHROUGH */
123208af722Sclaudio 	case LOG_BRIEF:
124d9ff5473Sclaudio 		if (control_compose(NULL, CTRL_LOG_VERBOSE,
125d9ff5473Sclaudio 		    &val, sizeof(int)) == -1)
126d9ff5473Sclaudio 			err(1, "control_compose");
1273471b912Sclaudio 		break;
128208af722Sclaudio 	case SHOW_SUM:
129d9ff5473Sclaudio 		if (control_compose(NULL, CTRL_SHOW_SUM, NULL, 0) == -1)
130d9ff5473Sclaudio 			err(1, "control_compose");
131d9ff5473Sclaudio 		break;
132d9ff5473Sclaudio 	case SHOW_SESS:
133208af722Sclaudio 		usage();
134208af722Sclaudio 		/* NOTREACHED */
135cf4672e7Sclaudio 	case SHOW_VSCSI_STATS:
136d9ff5473Sclaudio 		if (control_compose(NULL, CTRL_VSCSI_STATS, NULL, 0) == -1)
137d9ff5473Sclaudio 			err(1, "control_compose");
138cf4672e7Sclaudio 		break;
139208af722Sclaudio 	case RELOAD:
140208af722Sclaudio 		if ((cf = parse_config(confname)) == NULL)
141208af722Sclaudio 			errx(1, "errors while loading configuration file.");
1423471b912Sclaudio 		if (cf->initiator.isid_base != 0) {
143d9ff5473Sclaudio 			if (control_compose(NULL, CTRL_INITIATOR_CONFIG,
144d9ff5473Sclaudio 			    &cf->initiator, sizeof(cf->initiator)) == -1)
145d9ff5473Sclaudio 				err(1, "control_compose");
1463471b912Sclaudio 		}
1472f8c4829Sclaudio 
148208af722Sclaudio 		SIMPLEQ_FOREACH(s, &cf->sessions, entry) {
149d9ff5473Sclaudio 			struct ctrldata cdv[3];
150d9ff5473Sclaudio 			bzero(cdv, sizeof(cdv));
151d9ff5473Sclaudio 
152d9ff5473Sclaudio 			cdv[0].buf = &s->session;
153d9ff5473Sclaudio 			cdv[0].len = sizeof(s->session);
154d9ff5473Sclaudio 
155d9ff5473Sclaudio 			if (s->session.TargetName) {
156d9ff5473Sclaudio 				cdv[1].buf = s->session.TargetName;
157d9ff5473Sclaudio 				cdv[1].len =
158d9ff5473Sclaudio 				    strlen(s->session.TargetName) + 1;
159d9ff5473Sclaudio 			}
160d9ff5473Sclaudio 			if (s->session.InitiatorName) {
161d9ff5473Sclaudio 				cdv[2].buf = s->session.InitiatorName;
162d9ff5473Sclaudio 				cdv[2].len =
163d9ff5473Sclaudio 				    strlen(s->session.InitiatorName) + 1;
164d9ff5473Sclaudio 			}
165d9ff5473Sclaudio 
166d9ff5473Sclaudio 			if (control_build(NULL, CTRL_SESSION_CONFIG,
167d9ff5473Sclaudio 			    nitems(cdv), cdv) == -1)
168d9ff5473Sclaudio 				err(1, "control_build");
169208af722Sclaudio 		}
1702f8c4829Sclaudio 
1712f8c4829Sclaudio 		/* Reloading, so poll for connection establishment. */
1722f8c4829Sclaudio 		poll = 1;
173208af722Sclaudio 		break;
174208af722Sclaudio 	case DISCOVERY:
175208af722Sclaudio 		printf("discover %s\n", log_sockaddr(&res->addr));
176208af722Sclaudio 
177d9ff5473Sclaudio 		bzero(&sc, sizeof(sc));
178d9ff5473Sclaudio 		snprintf(sc.SessionName, sizeof(sc.SessionName),
179d9ff5473Sclaudio 		    "discovery.%d", (int)getpid());
180d9ff5473Sclaudio 		bcopy(&res->addr, &sc.connection.TargetAddr, res->addr.ss_len);
181d9ff5473Sclaudio 		sc.SessionType = SESSION_TYPE_DISCOVERY;
182d9ff5473Sclaudio 
183d9ff5473Sclaudio 		if (control_compose(NULL, CTRL_SESSION_CONFIG,
184d9ff5473Sclaudio 		    &sc, sizeof(sc)) == -1)
185d9ff5473Sclaudio 			err(1, "control_compose");
186208af722Sclaudio 	}
187208af722Sclaudio 
188d9ff5473Sclaudio 	run();
189d9ff5473Sclaudio 
1902f8c4829Sclaudio 	if (poll)
1912f8c4829Sclaudio 		poll_and_wait();
192208af722Sclaudio 
1932f8c4829Sclaudio 	close(control.fd);
194208af722Sclaudio 	return (0);
195208af722Sclaudio }
196208af722Sclaudio 
197208af722Sclaudio void
control_queue(void * ch,struct pdu * pdu)198d9ff5473Sclaudio control_queue(void *ch, struct pdu *pdu)
199d9ff5473Sclaudio {
200d9ff5473Sclaudio 	TAILQ_INSERT_TAIL(&control.channel, pdu, entry);
201d9ff5473Sclaudio }
202d9ff5473Sclaudio 
203d9ff5473Sclaudio void
run(void)204d9ff5473Sclaudio run(void)
205d9ff5473Sclaudio {
206d9ff5473Sclaudio 	struct pdu *pdu;
207d9ff5473Sclaudio 
208d9ff5473Sclaudio 	while ((pdu = TAILQ_FIRST(&control.channel)) != NULL) {
209d9ff5473Sclaudio 		TAILQ_REMOVE(&control.channel, pdu, entry);
210d9ff5473Sclaudio 		run_command(pdu);
211d9ff5473Sclaudio 	}
212d9ff5473Sclaudio }
213d9ff5473Sclaudio 
214d9ff5473Sclaudio void
run_command(struct pdu * pdu)215d9ff5473Sclaudio run_command(struct pdu *pdu)
216208af722Sclaudio {
217208af722Sclaudio 	struct ctrlmsghdr *cmh;
218208af722Sclaudio 	int done = 0;
219208af722Sclaudio 	ssize_t n;
220208af722Sclaudio 
221d9ff5473Sclaudio 	if (ctl_sendpdu(control.fd, pdu) == -1)
222208af722Sclaudio 		err(1, "send");
223208af722Sclaudio 	while (!done) {
224d9ff5473Sclaudio 		if ((n = recv(control.fd, cbuf, sizeof(cbuf), 0)) == -1 &&
225208af722Sclaudio 		    !(errno == EAGAIN || errno == EINTR))
226208af722Sclaudio 			err(1, "recv");
227208af722Sclaudio 
228208af722Sclaudio 		if (n == 0)
229208af722Sclaudio 			errx(1, "connection to iscsid closed");
230208af722Sclaudio 
231208af722Sclaudio 		pdu = ctl_getpdu(cbuf, n);
232208af722Sclaudio 		cmh = pdu_getbuf(pdu, NULL, 0);
233208af722Sclaudio 		if (cmh == NULL)
234208af722Sclaudio 			break;
235208af722Sclaudio 		switch (cmh->type) {
236208af722Sclaudio 		case CTRL_SUCCESS:
237208af722Sclaudio 			printf("command successful\n");
238208af722Sclaudio 			done = 1;
239208af722Sclaudio 			break;
240208af722Sclaudio 		case CTRL_FAILURE:
241208af722Sclaudio 			printf("command failed\n");
242208af722Sclaudio 			done = 1;
243208af722Sclaudio 			break;
2443471b912Sclaudio 		case CTRL_INPROGRESS:
2453471b912Sclaudio 			printf("command in progress...\n");
2463471b912Sclaudio 			break;
247d9ff5473Sclaudio 		case CTRL_INITIATOR_CONFIG:
248d9ff5473Sclaudio 		case CTRL_SESSION_CONFIG:
249d9ff5473Sclaudio 			show_config(cmh, pdu);
250d9ff5473Sclaudio 			break;
251cf4672e7Sclaudio 		case CTRL_VSCSI_STATS:
252cf4672e7Sclaudio 			show_vscsi_stats(cmh, pdu);
253cf4672e7Sclaudio 			done = 1;
254cf4672e7Sclaudio 			break;
2552f8c4829Sclaudio 		case CTRL_SESS_POLL:
2562f8c4829Sclaudio 			register_poll(cmh, pdu);
2572f8c4829Sclaudio 			done = 1;
2582f8c4829Sclaudio 			break;
2592f8c4829Sclaudio 
260208af722Sclaudio 		}
261208af722Sclaudio 	}
262208af722Sclaudio }
263208af722Sclaudio 
264208af722Sclaudio struct pdu *
ctl_getpdu(char * buf,size_t len)265208af722Sclaudio ctl_getpdu(char *buf, size_t len)
266208af722Sclaudio {
267208af722Sclaudio 	struct pdu *p;
268208af722Sclaudio 	struct ctrlmsghdr *cmh;
269208af722Sclaudio 	void *data;
270208af722Sclaudio 	size_t n;
271208af722Sclaudio 	int i;
272208af722Sclaudio 
273208af722Sclaudio 	if (len < sizeof(*cmh))
274208af722Sclaudio 		return NULL;
275208af722Sclaudio 
276208af722Sclaudio 	if (!(p = pdu_new()))
277208af722Sclaudio 		return NULL;
278208af722Sclaudio 
279208af722Sclaudio 	n = sizeof(*cmh);
280208af722Sclaudio 	cmh = pdu_alloc(n);
281208af722Sclaudio 	bcopy(buf, cmh, n);
282208af722Sclaudio 	buf += n;
283208af722Sclaudio 	len -= n;
284208af722Sclaudio 
285208af722Sclaudio 	if (pdu_addbuf(p, cmh, n, 0)) {
286208af722Sclaudio 		free(cmh);
287208af722Sclaudio fail:
288208af722Sclaudio 		pdu_free(p);
289208af722Sclaudio 		return NULL;
290208af722Sclaudio 	}
291208af722Sclaudio 
292208af722Sclaudio 	for (i = 0; i < 3; i++) {
293208af722Sclaudio 		n = cmh->len[i];
294208af722Sclaudio 		if (n == 0)
295208af722Sclaudio 			continue;
296208af722Sclaudio 		if (PDU_LEN(n) > len)
297208af722Sclaudio 			goto fail;
298208af722Sclaudio 		if (!(data = pdu_alloc(n)))
299208af722Sclaudio 			goto fail;
300208af722Sclaudio 		bcopy(buf, data, n);
301208af722Sclaudio 		if (pdu_addbuf(p, data, n, i + 1)) {
302208af722Sclaudio 			free(data);
303208af722Sclaudio 			goto fail;
304208af722Sclaudio 		}
305208af722Sclaudio 		buf += PDU_LEN(n);
306208af722Sclaudio 		len -= PDU_LEN(n);
307208af722Sclaudio 	}
308208af722Sclaudio 
309208af722Sclaudio 	return p;
310208af722Sclaudio }
311208af722Sclaudio 
312208af722Sclaudio int
ctl_sendpdu(int fd,struct pdu * pdu)313208af722Sclaudio ctl_sendpdu(int fd, struct pdu *pdu)
314208af722Sclaudio {
315208af722Sclaudio 	struct iovec iov[PDU_MAXIOV];
316208af722Sclaudio 	struct msghdr msg;
317208af722Sclaudio 	unsigned int niov = 0;
318208af722Sclaudio 
319208af722Sclaudio 	for (niov = 0; niov < PDU_MAXIOV; niov++) {
320208af722Sclaudio 		iov[niov].iov_base = pdu->iov[niov].iov_base;
321208af722Sclaudio 		iov[niov].iov_len = pdu->iov[niov].iov_len;
322208af722Sclaudio 	}
323208af722Sclaudio 	bzero(&msg, sizeof(msg));
324208af722Sclaudio 	msg.msg_iov = iov;
325208af722Sclaudio 	msg.msg_iovlen = niov;
326208af722Sclaudio 	if (sendmsg(fd, &msg, 0) == -1)
327208af722Sclaudio 		return -1;
328208af722Sclaudio 	return 0;
329208af722Sclaudio }
330cf4672e7Sclaudio 
331cf4672e7Sclaudio void
show_config(struct ctrlmsghdr * cmh,struct pdu * pdu)332d9ff5473Sclaudio show_config(struct ctrlmsghdr *cmh, struct pdu *pdu)
333d9ff5473Sclaudio {
334d9ff5473Sclaudio 	struct initiator_config	*ic;
335d9ff5473Sclaudio 	struct session_config	*sc;
3360ffafa02Sclaudio 	char *name;
337d9ff5473Sclaudio 
338d9ff5473Sclaudio 	switch (cmh->type) {
339d9ff5473Sclaudio 	case CTRL_INITIATOR_CONFIG:
340d9ff5473Sclaudio 		if (cmh->len[0] != sizeof(*ic))
341d9ff5473Sclaudio 			errx(1, "bad size of response");
342d9ff5473Sclaudio 		ic = pdu_getbuf(pdu, NULL, 1);
343d9ff5473Sclaudio 		if (ic == NULL)
344d9ff5473Sclaudio 			return;
345d9ff5473Sclaudio 
346*fcd50198Smbuhl 		printf("Initiator: ISID base %x qualifier %hx\n",
347d9ff5473Sclaudio 		    ic->isid_base, ic->isid_qual);
348d9ff5473Sclaudio 		break;
349d9ff5473Sclaudio 	case CTRL_SESSION_CONFIG:
350d9ff5473Sclaudio 		if (cmh->len[0] != sizeof(*sc))
351d9ff5473Sclaudio 			errx(1, "bad size of response");
352d9ff5473Sclaudio 		sc = pdu_getbuf(pdu, NULL, 1);
353d9ff5473Sclaudio 		if (sc == NULL)
354d9ff5473Sclaudio 			return;
355d9ff5473Sclaudio 
356d9ff5473Sclaudio 		printf("\nSession '%s':%s\n", sc->SessionName,
357d9ff5473Sclaudio 		    sc->disabled ? " disabled" : "");
358d9ff5473Sclaudio 		printf("    SessionType: %s\tMaxConnections: %hd\n",
359d9ff5473Sclaudio 		    sc->SessionType == SESSION_TYPE_DISCOVERY ? "discovery" :
360d9ff5473Sclaudio 		    "normal", sc->MaxConnections);
3610ffafa02Sclaudio 		if ((name = pdu_getbuf(pdu, NULL, 2)))
3620ffafa02Sclaudio 			printf("    TargetName: %s\n", name);
363d9ff5473Sclaudio 		printf("    TargetAddr: %s\n",
364d9ff5473Sclaudio 		    log_sockaddr(&sc->connection.TargetAddr));
3650ffafa02Sclaudio 		if ((name = pdu_getbuf(pdu, NULL, 3)))
3660ffafa02Sclaudio 			printf("    InitiatorName: %s\n", name);
3670ffafa02Sclaudio 		printf("    InitiatorAddr: %s\n",
3680ffafa02Sclaudio 		    log_sockaddr(&sc->connection.LocalAddr));
369d9ff5473Sclaudio 		break;
370d9ff5473Sclaudio 	}
371d9ff5473Sclaudio }
372d9ff5473Sclaudio 
373d9ff5473Sclaudio void
show_vscsi_stats(struct ctrlmsghdr * cmh,struct pdu * pdu)374cf4672e7Sclaudio show_vscsi_stats(struct ctrlmsghdr *cmh, struct pdu *pdu)
375cf4672e7Sclaudio {
376cf4672e7Sclaudio 	struct vscsi_stats *vs;
3772fe39d32Sclaudio 	char buf[FMT_SCALED_STRSIZE];
378cf4672e7Sclaudio 
379cf4672e7Sclaudio 	if (cmh->len[0] != sizeof(struct vscsi_stats))
380cf4672e7Sclaudio 		errx(1, "bad size of response");
381cf4672e7Sclaudio 	vs = pdu_getbuf(pdu, NULL, 1);
382cf4672e7Sclaudio 	if (vs == NULL)
383cf4672e7Sclaudio 		return;
384cf4672e7Sclaudio 
385cf4672e7Sclaudio 	printf("VSCSI ioctl statistics:\n");
386cf4672e7Sclaudio 	printf("%u probe calls and %u detach calls\n",
387cf4672e7Sclaudio 	    vs->cnt_probe, vs->cnt_detach);
388cf4672e7Sclaudio 	printf("%llu I2T calls (%llu read, %llu writes)\n",
389cf4672e7Sclaudio 	    vs->cnt_i2t,
390cf4672e7Sclaudio 	    vs->cnt_i2t_dir[1],
391cf4672e7Sclaudio 	    vs->cnt_i2t_dir[2]);
392cf4672e7Sclaudio 
3932fe39d32Sclaudio 	if (fmt_scaled(vs->bytes_rd, buf) != 0)
3942fe39d32Sclaudio 		(void)strlcpy(buf, "NaN", sizeof(buf));
3952fe39d32Sclaudio 	printf("%llu data reads (%s bytes read)\n", vs->cnt_read, buf);
3962fe39d32Sclaudio 	if (fmt_scaled(vs->bytes_wr, buf) != 0)
3972fe39d32Sclaudio 		(void)strlcpy(buf, "NaN", sizeof(buf));
3982fe39d32Sclaudio 	printf("%llu data writes (%s bytes written)\n", vs->cnt_write, buf);
399cf4672e7Sclaudio 
400cf4672e7Sclaudio 	printf("%llu T2I calls (%llu done, %llu sense errors, %llu errors)\n",
401cf4672e7Sclaudio 	    vs->cnt_t2i,
402cf4672e7Sclaudio 	    vs->cnt_t2i_status[0],
403cf4672e7Sclaudio 	    vs->cnt_t2i_status[1],
404cf4672e7Sclaudio 	    vs->cnt_t2i_status[2]);
405cf4672e7Sclaudio }
4062f8c4829Sclaudio 
4072f8c4829Sclaudio void
poll_session_status(void)4082f8c4829Sclaudio poll_session_status(void)
4092f8c4829Sclaudio {
4102f8c4829Sclaudio 	struct pdu *pdu;
4112f8c4829Sclaudio 
4122f8c4829Sclaudio 	if (control_compose(NULL, CTRL_SESS_POLL, NULL, 0) == -1)
4132f8c4829Sclaudio 		err(1, "control_compose");
4142f8c4829Sclaudio 
4152f8c4829Sclaudio 	while ((pdu = TAILQ_FIRST(&control.channel)) != NULL) {
4162f8c4829Sclaudio 		TAILQ_REMOVE(&control.channel, pdu, entry);
4172f8c4829Sclaudio 		run_command(pdu);
4182f8c4829Sclaudio 	}
4192f8c4829Sclaudio }
4202f8c4829Sclaudio 
4212f8c4829Sclaudio void
poll_and_wait(void)4222f8c4829Sclaudio poll_and_wait(void)
4232f8c4829Sclaudio {
4242f8c4829Sclaudio 	int attempts;
4252f8c4829Sclaudio 
4262f8c4829Sclaudio 	printf("waiting for config to settle..");
4272f8c4829Sclaudio 	fflush(stdout);
4282f8c4829Sclaudio 
4292f8c4829Sclaudio 	for (attempts = 0; attempts < POLL_ATTEMPTS; attempts++) {
4302f8c4829Sclaudio 
4312f8c4829Sclaudio 		poll_session_status();
4322f8c4829Sclaudio 
4332f8c4829Sclaudio 		/* Poll says we are good to go. */
4342f8c4829Sclaudio 		if (poll_result.sess_conn_status != 0) {
4352f8c4829Sclaudio 			printf("ok\n");
4362f8c4829Sclaudio 			/* wait a bit longer so all is settled. */
4372f8c4829Sclaudio 			sleep(POLL_DELAY_SEC);
4382f8c4829Sclaudio 			return;
4392f8c4829Sclaudio 		}
4402f8c4829Sclaudio 
4412f8c4829Sclaudio 		/* Poll says we should wait... */
4422f8c4829Sclaudio 		printf(".");
4432f8c4829Sclaudio 		fflush(stdout);
4442f8c4829Sclaudio 		sleep(POLL_DELAY_SEC);
4452f8c4829Sclaudio 	}
4462f8c4829Sclaudio 
4472f8c4829Sclaudio 	printf("giving up.\n");
4482f8c4829Sclaudio 
4492f8c4829Sclaudio 	poll_print(&poll_result);
4502f8c4829Sclaudio }
4512f8c4829Sclaudio 
4522f8c4829Sclaudio void
register_poll(struct ctrlmsghdr * cmh,struct pdu * pdu)4532f8c4829Sclaudio register_poll(struct ctrlmsghdr *cmh, struct pdu *pdu)
4542f8c4829Sclaudio {
4552f8c4829Sclaudio 	if (cmh->len[0] != sizeof(poll_result))
4562f8c4829Sclaudio 		errx(1, "poll: bad size of response");
4572f8c4829Sclaudio 
4582f8c4829Sclaudio 	poll_result = *((struct session_poll *)pdu_getbuf(pdu, NULL, 1));
4592f8c4829Sclaudio }
4602f8c4829Sclaudio 
4612f8c4829Sclaudio void
poll_print(struct session_poll * p)4622f8c4829Sclaudio poll_print(struct session_poll *p)
4632f8c4829Sclaudio {
4642f8c4829Sclaudio 	printf("Configured sessions: %d\n", p->session_count);
4652f8c4829Sclaudio 	printf("Sessions initializing: %d\n", p->session_init_count);
4662f8c4829Sclaudio 	printf("Sessions started/failed: %d\n", p->session_running_count);
4672f8c4829Sclaudio 	printf("Sessions logged in: %d\n", p->conn_logged_in_count);
4682f8c4829Sclaudio 	printf("Sessions with failed connections: %d\n", p->conn_failed_count);
4692f8c4829Sclaudio 	printf("Sessions still attempting to connect: %d\n",
4702f8c4829Sclaudio 	    p->conn_waiting_count);
4712f8c4829Sclaudio }
472