GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/iscsictl/iscsictl.c Lines: 0 184 0.0 %
Date: 2017-11-13 Branches: 0 112 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: iscsictl.c,v 1.11 2016/08/16 18:41:57 tedu Exp $ */
2
3
/*
4
 * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/queue.h>
20
#include <sys/socket.h>
21
#include <sys/uio.h>
22
#include <sys/un.h>
23
24
#include <event.h>
25
#include <err.h>
26
#include <errno.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
#include <util.h>
32
33
#include "iscsid.h"
34
#include "iscsictl.h"
35
36
__dead void	 usage(void);
37
void		 run(void);
38
void		 run_command(struct pdu *);
39
struct pdu	*ctl_getpdu(char *, size_t);
40
int		 ctl_sendpdu(int, struct pdu *);
41
void		 show_config(struct ctrlmsghdr *, struct pdu *);
42
void		 show_vscsi_stats(struct ctrlmsghdr *, struct pdu *);
43
44
char		cbuf[CONTROL_READ_SIZE];
45
46
struct control {
47
	struct pduq	channel;
48
	int		fd;
49
} control;
50
51
__dead void
52
usage(void)
53
{
54
	extern char *__progname;
55
56
	fprintf(stderr,"usage: %s [-s socket] command [argument ...]\n",
57
	    __progname);
58
	exit(1);
59
}
60
61
int
62
main (int argc, char* argv[])
63
{
64
	struct sockaddr_un sun;
65
	struct session_config sc;
66
	struct parse_result *res;
67
	char *confname = ISCSID_CONFIG;
68
	char *sockname = ISCSID_CONTROL;
69
	struct session_ctlcfg *s;
70
	struct iscsi_config *cf;
71
	int ch, val = 0;
72
73
	/* check flags */
74
	while ((ch = getopt(argc, argv, "f:s:")) != -1) {
75
		switch (ch) {
76
		case 'f':
77
			confname = optarg;
78
			break;
79
		case 's':
80
			sockname = optarg;
81
			break;
82
		default:
83
			usage();
84
			/* NOTREACHED */
85
		}
86
	}
87
	argc -= optind;
88
	argv += optind;
89
90
	/* parse options */
91
	if ((res = parse(argc, argv)) == NULL)
92
		exit(1);
93
94
	/* connect to iscsid control socket */
95
	TAILQ_INIT(&control.channel);
96
	if ((control.fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
97
		err(1, "socket");
98
99
	bzero(&sun, sizeof(sun));
100
	sun.sun_family = AF_UNIX;
101
	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
102
103
	if (connect(control.fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
104
		err(1, "connect: %s", sockname);
105
106
	if (pledge("stdio rpath dns flock cpath wpath", NULL) == -1)
107
		err(1, "pledge");
108
109
	switch (res->action) {
110
	case NONE:
111
	case LOG_VERBOSE:
112
		val = 1;
113
		/* FALLTHROUGH */
114
	case LOG_BRIEF:
115
		if (control_compose(NULL, CTRL_LOG_VERBOSE,
116
		    &val, sizeof(int)) == -1)
117
			err(1, "control_compose");
118
		break;
119
	case SHOW_SUM:
120
		if (control_compose(NULL, CTRL_SHOW_SUM, NULL, 0) == -1)
121
			err(1, "control_compose");
122
		break;
123
	case SHOW_SESS:
124
		usage();
125
		/* NOTREACHED */
126
	case SHOW_VSCSI_STATS:
127
		if (control_compose(NULL, CTRL_VSCSI_STATS, NULL, 0) == -1)
128
			err(1, "control_compose");
129
		break;
130
	case RELOAD:
131
		if ((cf = parse_config(confname)) == NULL)
132
			errx(1, "errors while loading configuration file.");
133
		if (cf->initiator.isid_base != 0) {
134
			if (control_compose(NULL, CTRL_INITIATOR_CONFIG,
135
			    &cf->initiator, sizeof(cf->initiator)) == -1)
136
				err(1, "control_compose");
137
		}
138
		SIMPLEQ_FOREACH(s, &cf->sessions, entry) {
139
			struct ctrldata cdv[3];
140
			bzero(cdv, sizeof(cdv));
141
142
			cdv[0].buf = &s->session;
143
			cdv[0].len = sizeof(s->session);
144
145
			if (s->session.TargetName) {
146
				cdv[1].buf = s->session.TargetName;
147
				cdv[1].len =
148
				    strlen(s->session.TargetName) + 1;
149
			}
150
			if (s->session.InitiatorName) {
151
				cdv[2].buf = s->session.InitiatorName;
152
				cdv[2].len =
153
				    strlen(s->session.InitiatorName) + 1;
154
			}
155
156
			if (control_build(NULL, CTRL_SESSION_CONFIG,
157
			    nitems(cdv), cdv) == -1)
158
				err(1, "control_build");
159
		}
160
		break;
161
	case DISCOVERY:
162
		printf("discover %s\n", log_sockaddr(&res->addr));
163
164
		bzero(&sc, sizeof(sc));
165
		snprintf(sc.SessionName, sizeof(sc.SessionName),
166
		    "discovery.%d", (int)getpid());
167
		bcopy(&res->addr, &sc.connection.TargetAddr, res->addr.ss_len);
168
		sc.SessionType = SESSION_TYPE_DISCOVERY;
169
170
		if (control_compose(NULL, CTRL_SESSION_CONFIG,
171
		    &sc, sizeof(sc)) == -1)
172
			err(1, "control_compose");
173
	}
174
175
	run();
176
177
	close(control.fd);
178
179
	return (0);
180
}
181
182
void
183
control_queue(void *ch, struct pdu *pdu)
184
{
185
	TAILQ_INSERT_TAIL(&control.channel, pdu, entry);
186
}
187
188
void
189
run(void)
190
{
191
	struct pdu *pdu;
192
193
	while ((pdu = TAILQ_FIRST(&control.channel)) != NULL) {
194
		TAILQ_REMOVE(&control.channel, pdu, entry);
195
		run_command(pdu);
196
	}
197
}
198
199
void
200
run_command(struct pdu *pdu)
201
{
202
	struct ctrlmsghdr *cmh;
203
	int done = 0;
204
	ssize_t n;
205
206
	if (ctl_sendpdu(control.fd, pdu) == -1)
207
		err(1, "send");
208
	while (!done) {
209
		if ((n = recv(control.fd, cbuf, sizeof(cbuf), 0)) == -1 &&
210
		    !(errno == EAGAIN || errno == EINTR))
211
			err(1, "recv");
212
213
		if (n == 0)
214
			errx(1, "connection to iscsid closed");
215
216
		pdu = ctl_getpdu(cbuf, n);
217
		cmh = pdu_getbuf(pdu, NULL, 0);
218
		if (cmh == NULL)
219
			break;
220
		switch (cmh->type) {
221
		case CTRL_SUCCESS:
222
			printf("command successful\n");
223
			done = 1;
224
			break;
225
		case CTRL_FAILURE:
226
			printf("command failed\n");
227
			done = 1;
228
			break;
229
		case CTRL_INPROGRESS:
230
			printf("command in progress...\n");
231
			break;
232
		case CTRL_INITIATOR_CONFIG:
233
		case CTRL_SESSION_CONFIG:
234
			show_config(cmh, pdu);
235
			break;
236
		case CTRL_VSCSI_STATS:
237
			show_vscsi_stats(cmh, pdu);
238
			done = 1;
239
			break;
240
		}
241
	}
242
}
243
244
struct pdu *
245
ctl_getpdu(char *buf, size_t len)
246
{
247
	struct pdu *p;
248
	struct ctrlmsghdr *cmh;
249
	void *data;
250
	size_t n;
251
	int i;
252
253
	if (len < sizeof(*cmh))
254
		return NULL;
255
256
	if (!(p = pdu_new()))
257
		return NULL;
258
259
	n = sizeof(*cmh);
260
	cmh = pdu_alloc(n);
261
	bcopy(buf, cmh, n);
262
	buf += n;
263
	len -= n;
264
265
	if (pdu_addbuf(p, cmh, n, 0)) {
266
		free(cmh);
267
fail:
268
		pdu_free(p);
269
		return NULL;
270
	}
271
272
	for (i = 0; i < 3; i++) {
273
		n = cmh->len[i];
274
		if (n == 0)
275
			continue;
276
		if (PDU_LEN(n) > len)
277
			goto fail;
278
		if (!(data = pdu_alloc(n)))
279
			goto fail;
280
		bcopy(buf, data, n);
281
		if (pdu_addbuf(p, data, n, i + 1)) {
282
			free(data);
283
			goto fail;
284
		}
285
		buf += PDU_LEN(n);
286
		len -= PDU_LEN(n);
287
	}
288
289
	return p;
290
}
291
292
int
293
ctl_sendpdu(int fd, struct pdu *pdu)
294
{
295
	struct iovec iov[PDU_MAXIOV];
296
	struct msghdr msg;
297
	unsigned int niov = 0;
298
299
	for (niov = 0; niov < PDU_MAXIOV; niov++) {
300
		iov[niov].iov_base = pdu->iov[niov].iov_base;
301
		iov[niov].iov_len = pdu->iov[niov].iov_len;
302
	}
303
	bzero(&msg, sizeof(msg));
304
	msg.msg_iov = iov;
305
	msg.msg_iovlen = niov;
306
	if (sendmsg(fd, &msg, 0) == -1)
307
		return -1;
308
	return 0;
309
}
310
311
void
312
show_config(struct ctrlmsghdr *cmh, struct pdu *pdu)
313
{
314
	struct initiator_config	*ic;
315
	struct session_config	*sc;
316
	char *name;
317
318
	switch (cmh->type) {
319
	case CTRL_INITIATOR_CONFIG:
320
		if (cmh->len[0] != sizeof(*ic))
321
			errx(1, "bad size of response");
322
		ic = pdu_getbuf(pdu, NULL, 1);
323
		if (ic == NULL)
324
			return;
325
326
		printf("Initiator: ISID base %x qalifier %hx\n",
327
		    ic->isid_base, ic->isid_qual);
328
		break;
329
	case CTRL_SESSION_CONFIG:
330
		if (cmh->len[0] != sizeof(*sc))
331
			errx(1, "bad size of response");
332
		sc = pdu_getbuf(pdu, NULL, 1);
333
		if (sc == NULL)
334
			return;
335
336
		printf("\nSession '%s':%s\n", sc->SessionName,
337
		    sc->disabled ? " disabled" : "");
338
		printf("    SessionType: %s\tMaxConnections: %hd\n",
339
		    sc->SessionType == SESSION_TYPE_DISCOVERY ? "discovery" :
340
		    "normal", sc->MaxConnections);
341
		if ((name = pdu_getbuf(pdu, NULL, 2)))
342
			printf("    TargetName: %s\n", name);
343
		printf("    TargetAddr: %s\n",
344
		    log_sockaddr(&sc->connection.TargetAddr));
345
		if ((name = pdu_getbuf(pdu, NULL, 3)))
346
			printf("    InitiatorName: %s\n", name);
347
		printf("    InitiatorAddr: %s\n",
348
		    log_sockaddr(&sc->connection.LocalAddr));
349
		break;
350
	}
351
}
352
353
void
354
show_vscsi_stats(struct ctrlmsghdr *cmh, struct pdu *pdu)
355
{
356
	struct vscsi_stats *vs;
357
	char buf[FMT_SCALED_STRSIZE];
358
359
	if (cmh->len[0] != sizeof(struct vscsi_stats))
360
		errx(1, "bad size of response");
361
	vs = pdu_getbuf(pdu, NULL, 1);
362
	if (vs == NULL)
363
		return;
364
365
	printf("VSCSI ioctl statistics:\n");
366
	printf("%u probe calls and %u detach calls\n",
367
	    vs->cnt_probe, vs->cnt_detach);
368
	printf("%llu I2T calls (%llu read, %llu writes)\n",
369
	    vs->cnt_i2t,
370
	    vs->cnt_i2t_dir[1],
371
	    vs->cnt_i2t_dir[2]);
372
373
	if (fmt_scaled(vs->bytes_rd, buf) != 0)
374
		(void)strlcpy(buf, "NaN", sizeof(buf));
375
	printf("%llu data reads (%s bytes read)\n", vs->cnt_read, buf);
376
	if (fmt_scaled(vs->bytes_wr, buf) != 0)
377
		(void)strlcpy(buf, "NaN", sizeof(buf));
378
	printf("%llu data writes (%s bytes written)\n", vs->cnt_write, buf);
379
380
	printf("%llu T2I calls (%llu done, %llu sense errors, %llu errors)\n",
381
	    vs->cnt_t2i,
382
	    vs->cnt_t2i_status[0],
383
	    vs->cnt_t2i_status[1],
384
	    vs->cnt_t2i_status[2]);
385
}