xref: /openbsd-src/usr.sbin/iscsictl/iscsictl.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: iscsictl.c,v 1.3 2011/04/27 19:20:01 claudio 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/types.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/uio.h>
23 #include <sys/un.h>
24 
25 #include <event.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include "iscsid.h"
34 #include "iscsictl.h"
35 
36 __dead void	 usage(void);
37 void		 run_command(int, struct pdu *);
38 struct pdu	*ctl_getpdu(char *, size_t);
39 int		 ctl_sendpdu(int, struct pdu *);
40 
41 char		cbuf[CONTROL_READ_SIZE];
42 
43 __dead void
44 usage(void)
45 {
46 	extern char *__progname;
47 
48 	fprintf(stderr,"usage: %s [-s socket] command [argument ...]\n",
49 	    __progname);
50 	exit(1);
51 }
52 
53 int
54 main (int argc, char* argv[])
55 {
56 	struct sockaddr_un sun;
57 	struct parse_result *res;
58 	char *confname = ISCSID_CONFIG;
59 	char *sockname = ISCSID_CONTROL;
60 	struct pdu *pdu;
61 	struct ctrlmsghdr *cmh;
62 	struct session_config *sc;
63 	struct initiator_config *ic;
64 	struct session_ctlcfg *s;
65 	struct iscsi_config *cf;
66 	char *tname, *iname;
67 	int ch, csock;
68 	int *vp, val = 0;
69 
70 	/* check flags */
71 	while ((ch = getopt(argc, argv, "f:s:")) != -1) {
72 		switch (ch) {
73 		case 'f':
74 			confname = optarg;
75 			break;
76 		case 's':
77 			sockname = optarg;
78 			break;
79 		default:
80 			usage();
81 			/* NOTREACHED */
82 		}
83 	}
84 	argc -= optind;
85 	argv += optind;
86 
87 	/* parse options */
88 	if ((res = parse(argc, argv)) == NULL)
89 		exit(1);
90 
91 	/* connect to ospfd control socket */
92 	if ((csock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
93 		err(1, "socket");
94 
95 	bzero(&sun, sizeof(sun));
96 	sun.sun_family = AF_UNIX;
97 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
98 
99 	if (connect(csock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
100 		err(1, "connect: %s", sockname);
101 
102 	switch (res->action) {
103 	case NONE:
104 	case LOG_VERBOSE:
105 		val = 1;
106 		/* FALLTHROUGH */
107 	case LOG_BRIEF:
108 		if ((pdu = pdu_new()) == NULL)
109 			err(1, "pdu_new");
110 		if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL)
111 			err(1, "pdu_alloc");
112 		bzero(cmh, sizeof(*cmh));
113 		cmh->type = CTRL_LOG_VERBOSE;
114 		cmh->len[0] = sizeof(int);
115 		if ((vp = pdu_dup(&val, sizeof(int))) == NULL)
116 			err(1, "pdu_dup");
117 		pdu_addbuf(pdu, cmh, sizeof(*cmh), 0);
118 		pdu_addbuf(pdu, vp, sizeof(int), 1);
119 		run_command(csock, pdu);
120 		break;
121 	case SHOW:
122 	case SHOW_SUM:
123 		usage();
124 		/* NOTREACHED */
125 	case RELOAD:
126 		if ((cf = parse_config(confname)) == NULL)
127 			errx(1, "errors while loading configuration file.");
128 		if (cf->initiator.isid_base != 0) {
129 			if ((pdu = pdu_new()) == NULL)
130 				err(1, "pdu_new");
131 			if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL)
132 				err(1, "pdu_alloc");
133 			bzero(cmh, sizeof(*cmh));
134 			cmh->type = CTRL_INITIATOR_CONFIG;
135 			cmh->len[0] = sizeof(*ic);
136 			if ((ic = pdu_dup(&cf->initiator,
137 			    sizeof(cf->initiator))) == NULL)
138 				err(1, "pdu_dup");
139 			pdu_addbuf(pdu, cmh, sizeof(*cmh), 0);
140 			pdu_addbuf(pdu, ic, sizeof(*ic), 1);
141 			run_command(csock, pdu);
142 		}
143 		SIMPLEQ_FOREACH(s, &cf->sessions, entry) {
144 			if ((pdu = pdu_new()) == NULL)
145 				err(1, "pdu_new");
146 			if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL)
147 				err(1, "pdu_alloc");
148 			bzero(cmh, sizeof(*cmh));
149 			cmh->type = CTRL_SESSION_CONFIG;
150 			cmh->len[0] = sizeof(*sc);
151 			if ((sc = pdu_dup(&s->session, sizeof(s->session))) ==
152 			    NULL)
153 				err(1, "pdu_dup");
154 			if (s->session.TargetName) {
155 				if ((tname = pdu_dup(s->session.TargetName,
156 				    strlen(s->session.TargetName) + 1)) ==
157 				    NULL)
158 					err(1, "pdu_dup");
159 				cmh->len[1] = strlen(s->session.TargetName) + 1;
160 			} else
161 				tname = NULL;
162 			if (s->session.InitiatorName) {
163 				if ((iname = pdu_dup(s->session.InitiatorName,
164 				    strlen(s->session.InitiatorName) + 1)) ==
165 				    NULL)
166 					err(1, "pdu_dup");
167 				cmh->len[2] = strlen(s->session.InitiatorName)
168 				    + 1;
169 			} else
170 				iname = NULL;
171 			pdu_addbuf(pdu, cmh, sizeof(*cmh), 0);
172 			pdu_addbuf(pdu, sc, sizeof(*sc), 1);
173 			if (tname)
174 				pdu_addbuf(pdu, tname, strlen(tname) + 1, 2);
175 			if (iname)
176 				pdu_addbuf(pdu, iname, strlen(iname) + 1, 3);
177 
178 			run_command(csock, pdu);
179 		}
180 		break;
181 	case DISCOVERY:
182 		printf("discover %s\n", log_sockaddr(&res->addr));
183 		if ((pdu = pdu_new()) == NULL)
184 			err(1, "pdu_new");
185 		if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL)
186 			err(1, "pdu_alloc");
187 		if ((sc = pdu_alloc(sizeof(*sc))) == NULL)
188 			err(1, "pdu_alloc");
189 		bzero(cmh, sizeof(*cmh));
190 		bzero(sc, sizeof(*sc));
191 		snprintf(sc->SessionName, sizeof(sc->SessionName),
192 		    "discovery.%d", (int)getpid());
193 		bcopy(&res->addr, &sc->connection.TargetAddr, res->addr.ss_len);
194 		sc->SessionType = SESSION_TYPE_DISCOVERY;
195 		cmh->type = CTRL_SESSION_CONFIG;
196 		cmh->len[0] = sizeof(*sc);
197 		pdu_addbuf(pdu, cmh, sizeof(*cmh), 0);
198 		pdu_addbuf(pdu, sc, sizeof(*sc), 1);
199 
200 		run_command(csock, pdu);
201 	}
202 
203 	close(csock);
204 
205 	return (0);
206 }
207 
208 void
209 run_command(int csock, struct pdu *pdu)
210 {
211 	struct ctrlmsghdr *cmh;
212 	int done = 0;
213 	ssize_t n;
214 
215 	if (ctl_sendpdu(csock, pdu) == -1)
216 		err(1, "send");
217 	while (!done) {
218 		if ((n = recv(csock, cbuf, sizeof(cbuf), 0)) == -1 &&
219 		    !(errno == EAGAIN || errno == EINTR))
220 			err(1, "recv");
221 
222 		if (n == 0)
223 			errx(1, "connection to iscsid closed");
224 
225 		pdu = ctl_getpdu(cbuf, n);
226 		cmh = pdu_getbuf(pdu, NULL, 0);
227 			if (cmh == NULL)
228 				break;
229 		switch (cmh->type) {
230 		case CTRL_SUCCESS:
231 			printf("command successful\n");
232 			done = 1;
233 			break;
234 		case CTRL_FAILURE:
235 			printf("command failed\n");
236 			done = 1;
237 			break;
238 		case CTRL_INPROGRESS:
239 			printf("command in progress...\n");
240 			break;
241 		}
242 	}
243 }
244 
245 struct pdu *
246 ctl_getpdu(char *buf, size_t len)
247 {
248 	struct pdu *p;
249 	struct ctrlmsghdr *cmh;
250 	void *data;
251 	size_t n;
252 	int i;
253 
254 	if (len < sizeof(*cmh))
255 		return NULL;
256 
257 	if (!(p = pdu_new()))
258 		return NULL;
259 
260 	n = sizeof(*cmh);
261 	cmh = pdu_alloc(n);
262 	bcopy(buf, cmh, n);
263 	buf += n;
264 	len -= n;
265 
266 	if (pdu_addbuf(p, cmh, n, 0)) {
267 		free(cmh);
268 fail:
269 		pdu_free(p);
270 		return NULL;
271 	}
272 
273 	for (i = 0; i < 3; i++) {
274 		n = cmh->len[i];
275 		if (n == 0)
276 			continue;
277 		if (PDU_LEN(n) > len)
278 			goto fail;
279 		if (!(data = pdu_alloc(n)))
280 			goto fail;
281 		bcopy(buf, data, n);
282 		if (pdu_addbuf(p, data, n, i + 1)) {
283 			free(data);
284 			goto fail;
285 		}
286 		buf += PDU_LEN(n);
287 		len -= PDU_LEN(n);
288 	}
289 
290 	return p;
291 }
292 
293 int
294 ctl_sendpdu(int fd, struct pdu *pdu)
295 {
296 	struct iovec iov[PDU_MAXIOV];
297 	struct msghdr msg;
298 	unsigned int niov = 0;
299 
300 	for (niov = 0; niov < PDU_MAXIOV; niov++) {
301 		iov[niov].iov_base = pdu->iov[niov].iov_base;
302 		iov[niov].iov_len = pdu->iov[niov].iov_len;
303 	}
304 	bzero(&msg, sizeof(msg));
305 	msg.msg_iov = iov;
306 	msg.msg_iovlen = niov;
307 	if (sendmsg(fd, &msg, 0) == -1)
308 		return -1;
309 	return 0;
310 }
311