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