1 1.6 joerg /* $NetBSD: iscsic_main.c,v 1.6 2015/05/30 15:57:32 joerg Exp $ */ 2 1.1 agc 3 1.1 agc /*- 4 1.1 agc * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 1.1 agc * All rights reserved. 6 1.1 agc * 7 1.1 agc * This code is derived from software contributed to The NetBSD Foundation 8 1.1 agc * by Wasabi Systems, Inc. 9 1.1 agc * 10 1.1 agc * Redistribution and use in source and binary forms, with or without 11 1.1 agc * modification, are permitted provided that the following conditions 12 1.1 agc * are met: 13 1.1 agc * 1. Redistributions of source code must retain the above copyright 14 1.1 agc * notice, this list of conditions and the following disclaimer. 15 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 agc * notice, this list of conditions and the following disclaimer in the 17 1.1 agc * documentation and/or other materials provided with the distribution. 18 1.1 agc * 19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 agc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 agc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 agc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 agc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 agc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 agc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 agc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 agc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 agc * POSSIBILITY OF SUCH DAMAGE. 30 1.1 agc */ 31 1.1 agc #include <sys/types.h> 32 1.1 agc #include <sys/param.h> 33 1.1 agc #include <sys/socket.h> 34 1.1 agc #include <sys/un.h> 35 1.1 agc 36 1.1 agc #include "iscsic_globals.h" 37 1.1 agc 38 1.1 agc #include <err.h> 39 1.1 agc #include <errno.h> 40 1.1 agc #include <fcntl.h> 41 1.1 agc #include <stdarg.h> 42 1.1 agc 43 1.1 agc #define DEVICE "/dev/iscsi0" 44 1.1 agc 45 1.1 agc #define ISCSICTL_VERSION "20110805" 46 1.1 agc 47 1.1 agc /* 48 1.1 agc *-------- Table of commands and the associated handler function ------------- 49 1.1 agc */ 50 1.1 agc 51 1.1 agc static command_t cmds[] = { 52 1.1 agc {"version", get_version}, 53 1.1 agc {"add_target", add_target}, 54 1.1 agc {"add_portal", add_portal}, 55 1.1 agc {"remove_target", remove_target}, 56 1.1 agc {"slp_find_targets", slp_find_targets}, 57 1.1 agc {"refresh_targets", refresh_targets}, 58 1.1 agc {"list_targets", list_targets}, 59 1.1 agc {"add_send_target", add_send_target}, 60 1.1 agc {"remove_send_target", remove_send_target}, 61 1.1 agc {"list_send_targets", list_send_targets}, 62 1.1 agc {"add_isns_server", add_isns_server}, 63 1.1 agc {"remove_isns_server", remove_isns_server}, 64 1.1 agc {"find_isns_servers", find_isns_servers}, 65 1.1 agc {"list_isns_servers", list_isns_servers}, 66 1.1 agc {"refresh_isns", refresh_isns}, 67 1.1 agc {"login", login}, 68 1.1 agc {"logout", logout}, 69 1.1 agc {"add_connection", add_connection}, 70 1.1 agc {"remove_connection", remove_connection}, 71 1.1 agc {"inquiry", inquiry}, 72 1.1 agc {"read_capacity", read_capacity}, 73 1.1 agc {"report_luns", report_luns}, 74 1.1 agc {"test_unit_ready", test_unit_ready}, 75 1.1 agc {"add_initiator", add_initiator}, 76 1.1 agc {"remove_initiator", remove_initiator}, 77 1.1 agc {"list_initiators", list_initiators}, 78 1.1 agc {"list_sessions", list_sessions}, 79 1.1 agc {"set_node_name", set_node_name}, 80 1.1 agc {NULL, NULL} 81 1.1 agc }; 82 1.1 agc 83 1.1 agc 84 1.1 agc /* 85 1.1 agc *-------- Table of error codes and the associated message text ------------- 86 1.1 agc */ 87 1.1 agc 88 1.1 agc typedef struct { 89 1.1 agc unsigned code; 90 1.1 agc const char *str; 91 1.1 agc } status_msg_t; 92 1.1 agc 93 1.1 agc static status_msg_t status_msg[] = { 94 1.1 agc {ISCSI_STATUS_LIST_EMPTY, "The list is empty"}, 95 1.1 agc {ISCSI_STATUS_DUPLICATE_NAME, "The specified name is not unique"}, 96 1.1 agc {ISCSI_STATUS_GENERAL_ERROR, "A non-specific error occurred"}, 97 1.1 agc {ISCSI_STATUS_LOGIN_FAILED, "The login failed"}, 98 1.1 agc {ISCSI_STATUS_CONNECTION_FAILED, "The attempt to establish a connection failed"}, 99 1.1 agc {ISCSI_STATUS_AUTHENTICATION_FAILED, "Authentication negotiation failed"}, 100 1.1 agc {ISCSI_STATUS_NO_RESOURCES, "Could not allocate resources (e.g. memory)"}, 101 1.1 agc {ISCSI_STATUS_MAXED_CONNECTIONS, "Maximum number of connections exceeded"}, 102 1.1 agc {ISCSI_STATUS_INVALID_SESSION_ID, "Session ID not found"}, 103 1.1 agc {ISCSI_STATUS_INVALID_CONNECTION_ID, "Connection ID not found"}, 104 1.1 agc {ISCSI_STATUS_INVALID_SOCKET, "Specified socket is invalid"}, 105 1.1 agc {ISCSI_STATUS_NOTIMPL, "Feature not implemented"}, 106 1.1 agc {ISCSI_STATUS_CHECK_CONDITION, "Target reported CHECK CONDITION"}, 107 1.1 agc {ISCSI_STATUS_TARGET_BUSY, "Target reported BUSY"}, 108 1.1 agc {ISCSI_STATUS_TARGET_ERROR, "Target reported other error"}, 109 1.1 agc {ISCSI_STATUS_TARGET_FAILURE, "Command Response was Target Failure"}, 110 1.1 agc {ISCSI_STATUS_TARGET_DROP, "Target dropped connection"}, 111 1.1 agc {ISCSI_STATUS_SOCKET_ERROR, "Communication failure"}, 112 1.1 agc {ISCSI_STATUS_PARAMETER_MISSING, "A required ioctl parameter is missing"}, 113 1.1 agc {ISCSI_STATUS_PARAMETER_INVALID, "A parameter is malformed (string too long etc.)"}, 114 1.1 agc {ISCSI_STATUS_MAP_FAILED, "Mapping the LUNs failed"}, 115 1.1 agc {ISCSI_STATUS_NO_INITIATOR_NAME, "Initiator name not set"}, 116 1.1 agc {ISCSI_STATUS_NEGOTIATION_ERROR, "Negotiation failure (invalid key or value)"}, 117 1.1 agc {ISCSI_STATUS_TIMEOUT, "Command timed out (at iSCSI level)"}, 118 1.1 agc {ISCSI_STATUS_PROTOCOL_ERROR, "Internal Error (Protocol error reject)"}, 119 1.1 agc {ISCSI_STATUS_PDU_ERROR, "Internal Error (Invalid PDU field reject)"}, 120 1.1 agc {ISCSI_STATUS_CMD_NOT_SUPPORTED, "Target does not support iSCSI command"}, 121 1.1 agc {ISCSI_STATUS_DRIVER_UNLOAD, "Driver is unloading"}, 122 1.1 agc {ISCSI_STATUS_LOGOUT, "Session was logged out"}, 123 1.1 agc {ISCSI_STATUS_PDUS_LOST, "Excessive PDU loss"}, 124 1.1 agc {ISCSI_STATUS_INVALID_EVENT_ID, "Invalid Event ID"}, 125 1.1 agc {ISCSI_STATUS_EVENT_DEREGISTERED, "Wait for event cancelled by deregistration"}, 126 1.1 agc {ISCSI_STATUS_EVENT_WAITING, "Already waiting for event"}, 127 1.1 agc {ISCSI_STATUS_TASK_NOT_FOUND, "Task Management: task not found"}, 128 1.1 agc {ISCSI_STATUS_LUN_NOT_FOUND, "Task Management: LUN not found"}, 129 1.1 agc {ISCSI_STATUS_TASK_ALLEGIANT, "Task Management: Task still allegiant"}, 130 1.1 agc {ISCSI_STATUS_CANT_REASSIGN, "Task Management: Task reassignment not supported"}, 131 1.1 agc {ISCSI_STATUS_FUNCTION_UNSUPPORTED, "Task Management: Function unsupported"}, 132 1.1 agc {ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED, "Task Management: Function not authorized"}, 133 1.1 agc {ISCSI_STATUS_FUNCTION_REJECTED, "Task Management: Function rejected"}, 134 1.1 agc {ISCSI_STATUS_UNKNOWN_REASON, "Task Management: Unknown reason code"}, 135 1.1 agc {ISCSI_STATUS_DUPLICATE_ID, "Duplicate ID"}, 136 1.1 agc {ISCSI_STATUS_INVALID_ID, "ID not found"}, 137 1.1 agc {ISCSI_STATUS_TARGET_LOGOUT, "Target requested logout"}, 138 1.1 agc {ISCSI_STATUS_LOGOUT_CID_NOT_FOUND, "Logout error: Connection ID not found"}, 139 1.1 agc {ISCSI_STATUS_LOGOUT_RECOVERY_NS, "Logout error: Recovery not supported"}, 140 1.1 agc {ISCSI_STATUS_LOGOUT_ERROR, "Logout error: Unknown reason"}, 141 1.1 agc 142 1.1 agc {ISCSID_STATUS_LIST_EMPTY, "The list is empty"}, 143 1.1 agc {ISCSID_STATUS_DUPLICATE_NAME, "The specified name is not unique"}, 144 1.1 agc {ISCSID_STATUS_GENERAL_ERROR, "A non-specific error occurred"}, 145 1.1 agc {ISCSID_STATUS_CONNECT_ERROR, "Failed to connect to target"}, 146 1.1 agc {ISCSID_STATUS_NO_RESOURCES, "Could not allocate resources (e.g. memory)"}, 147 1.1 agc {ISCSID_STATUS_INVALID_SESSION_ID, "Session ID not found"}, 148 1.1 agc {ISCSID_STATUS_INVALID_CONNECTION_ID, "Connection ID not found"}, 149 1.1 agc {ISCSID_STATUS_NOTIMPL, "Feature not implemented"}, 150 1.1 agc {ISCSID_STATUS_SOCKET_ERROR, "Failed to create socket"}, 151 1.1 agc {ISCSID_STATUS_PARAMETER_MISSING, "A required parameter is missing"}, 152 1.1 agc {ISCSID_STATUS_PARAMETER_INVALID, "Request parameter is invalid"}, 153 1.1 agc {ISCSID_STATUS_NO_INITIATOR_NAME, "Initiator name was not set"}, 154 1.1 agc {ISCSID_STATUS_TIMEOUT, "Request timed out"}, 155 1.1 agc {ISCSID_STATUS_DRIVER_NOT_LOADED, "iSCSI Driver not loaded"}, 156 1.1 agc {ISCSID_STATUS_INVALID_REQUEST, "Unknown request code"}, 157 1.1 agc {ISCSID_STATUS_INVALID_PORTAL_ID, "Portal ID not found"}, 158 1.1 agc {ISCSID_STATUS_INVALID_TARGET_ID, "Target ID not found"}, 159 1.1 agc {ISCSID_STATUS_NOT_FOUND, "Requested item not found"}, 160 1.1 agc {ISCSID_STATUS_HOST_NOT_FOUND, "Target address not found"}, 161 1.1 agc {ISCSID_STATUS_HOST_TRY_AGAIN, "Target address retrieval failed, try again later"}, 162 1.1 agc {ISCSID_STATUS_HOST_ERROR, "Target address invalid"}, 163 1.1 agc {ISCSID_STATUS_NO_TARGETS_FOUND, "No targets found"}, 164 1.1 agc {ISCSID_STATUS_INVALID_ISNS_ID, "iSNS ID not found"}, 165 1.1 agc {ISCSID_STATUS_ISNS_ERROR, "Problem connecting to iSNS"}, 166 1.1 agc {ISCSID_STATUS_ISNS_SERVER_ERROR, "iSNS server returned garbage"}, 167 1.1 agc {ISCSID_STATUS_DUPLICATE_ENTRY, "The entry already exists"}, 168 1.1 agc {ISCSID_STATUS_INVALID_INITIATOR_ID, "Initiator ID not found"}, 169 1.1 agc {ISCSID_STATUS_INITIATOR_BIND_ERROR, "Bind to initiator portal failed"}, 170 1.1 agc 171 1.1 agc {0, NULL} 172 1.1 agc }; 173 1.1 agc 174 1.1 agc /* -------------------------------------------------------------------------- */ 175 1.1 agc /* local variables */ 176 1.1 agc 177 1.1 agc static struct sockaddr_un daemon_name; /* daemon socket name */ 178 1.1 agc 179 1.1 agc static char sockdir[MAXPATHLEN]; /* where myname lives */ 180 1.1 agc static struct sockaddr_un myname; /* my socket name */ 181 1.1 agc static int sock; /* the socket */ 182 1.1 agc 183 1.1 agc static char *cmdname; /* pointer to command name for error msgs */ 184 1.1 agc 185 1.1 agc /* global variables */ 186 1.1 agc 187 1.1 agc uint8_t buf[BUF_SIZE]; /* buffer for daemon comm and driver I/O */ 188 1.1 agc 189 1.1 agc int driver; /* driver handle */ 190 1.1 agc 191 1.1 agc /* -------------------------------------------------------------------------- */ 192 1.1 agc 193 1.1 agc #define progname getprogname() 194 1.1 agc 195 1.1 agc 196 1.1 agc /* 197 1.1 agc * bye: 198 1.1 agc * Cleanup and exit. Does not return. 199 1.1 agc */ 200 1.1 agc 201 1.4 joerg __dead static void 202 1.1 agc bye(void) 203 1.1 agc { 204 1.1 agc close(sock); 205 1.1 agc (void) unlink(myname.sun_path); 206 1.1 agc (void) rmdir(sockdir); 207 1.1 agc exit(EXIT_FAILURE); 208 1.1 agc } 209 1.1 agc 210 1.1 agc 211 1.1 agc /* 212 1.1 agc * arg_error: 213 1.1 agc * Display error message about an invalid argument, exit. 214 1.1 agc * 215 1.1 agc * Parameters: 216 1.1 agc * argp Argument value 217 1.1 agc * fmt Error message 218 1.1 agc * ... additional output arguments 219 1.1 agc * 220 1.1 agc * Does not return. 221 1.1 agc */ 222 1.1 agc 223 1.1 agc void 224 1.1 agc arg_error(char *argp, const char *fmt, ...) 225 1.1 agc { 226 1.1 agc va_list args; 227 1.1 agc char lbuf[BUF_SIZE]; 228 1.1 agc 229 1.1 agc va_start(args, fmt); 230 1.1 agc vsnprintf(lbuf, sizeof(lbuf), fmt, args); 231 1.1 agc fprintf(stderr, "%s: %s: Invalid option at or near '%s': %s\n", 232 1.1 agc progname, cmdname, argp, lbuf); 233 1.1 agc bye(); 234 1.1 agc } 235 1.1 agc 236 1.1 agc 237 1.1 agc /* 238 1.1 agc * arg_missing: 239 1.1 agc * Display error message about a missing argument, exit. 240 1.1 agc * 241 1.1 agc * Parameters: 242 1.1 agc * arg Argument name 243 1.1 agc * 244 1.1 agc * Does not return. 245 1.1 agc */ 246 1.1 agc 247 1.1 agc void 248 1.1 agc arg_missing(const char *arg) 249 1.1 agc { 250 1.1 agc warnx("%s: Missing argument: %s", cmdname, arg); 251 1.1 agc bye(); 252 1.1 agc } 253 1.1 agc 254 1.1 agc 255 1.1 agc /* 256 1.1 agc * io_error: 257 1.1 agc * Display error message about an I/O error (includes system error code) 258 1.1 agc * 259 1.1 agc * Parameters: 260 1.1 agc * fmt format string 261 1.1 agc * ... additional output arguments 262 1.1 agc * 263 1.1 agc * Does not return. 264 1.1 agc */ 265 1.1 agc 266 1.1 agc void 267 1.1 agc io_error(const char *fmt, ...) 268 1.1 agc { 269 1.1 agc va_list args; 270 1.1 agc char lbuf[BUF_SIZE]; 271 1.1 agc 272 1.1 agc va_start(args, fmt); 273 1.1 agc vsnprintf(lbuf, sizeof(lbuf), fmt, args); 274 1.1 agc fprintf(stderr, "%s: %s: %s: %s\n", 275 1.1 agc progname, cmdname, lbuf, strerror(errno)); 276 1.1 agc bye(); 277 1.1 agc } 278 1.1 agc 279 1.1 agc 280 1.1 agc /* 281 1.1 agc * gen_error: 282 1.1 agc * Display general error message. 283 1.1 agc * 284 1.1 agc * Parameters: 285 1.1 agc * fmt format string 286 1.1 agc * ... additional output arguments 287 1.1 agc * 288 1.1 agc * Does not return. 289 1.1 agc */ 290 1.1 agc 291 1.1 agc void 292 1.1 agc gen_error(const char *fmt, ...) 293 1.1 agc { 294 1.1 agc va_list args; 295 1.1 agc char lbuf[BUF_SIZE]; 296 1.1 agc 297 1.1 agc va_start(args, fmt); 298 1.1 agc vsnprintf(lbuf, sizeof(lbuf), fmt, args); 299 1.1 agc fprintf(stderr, "%s: %s: %s\n", progname, cmdname, lbuf); 300 1.1 agc bye(); 301 1.1 agc } 302 1.1 agc 303 1.1 agc 304 1.1 agc /* 305 1.1 agc * check_extra_args: 306 1.1 agc * Display error message & exit if there is an unrecognized argument. 307 1.1 agc * 308 1.1 agc * Parameters: 309 1.1 agc * argc Argument count 310 1.1 agc * argv Argument value array. 311 1.1 agc * 312 1.1 agc * Does not return if an extra arg is found. 313 1.1 agc */ 314 1.1 agc 315 1.1 agc void 316 1.1 agc check_extra_args(int argc, char **argv) 317 1.1 agc { 318 1.1 agc int i; 319 1.1 agc 320 1.1 agc for (i = 0; i < argc; i++) 321 1.1 agc if (argv[i] != NULL) { 322 1.1 agc warnx("%s: Unrecognized argument '%s'", cmdname, argv[i]); 323 1.1 agc bye(); 324 1.1 agc } 325 1.1 agc } 326 1.1 agc 327 1.1 agc 328 1.1 agc /* 329 1.1 agc * status_error: 330 1.1 agc * Display error message for status returned by daemon or driver, exit. 331 1.1 agc * 332 1.1 agc * Parameters: 333 1.1 agc * n Status code. 334 1.1 agc * 335 1.1 agc * Does not return. 336 1.1 agc */ 337 1.1 agc 338 1.1 agc void 339 1.1 agc status_error(unsigned n) 340 1.1 agc { 341 1.1 agc int i; 342 1.1 agc 343 1.1 agc for (i = 0; status_msg[i].code; i++) 344 1.1 agc if (status_msg[i].code == n) 345 1.1 agc break; 346 1.1 agc 347 1.1 agc if (status_msg[i].code) 348 1.1 agc warnx("%s: %s", cmdname, status_msg[i].str); 349 1.1 agc else 350 1.1 agc warnx("%s: Undefined error code %d", cmdname, n); 351 1.1 agc 352 1.1 agc bye(); 353 1.1 agc } 354 1.1 agc 355 1.1 agc 356 1.1 agc /* 357 1.1 agc * status_error_slist: 358 1.1 agc * Display error message for status returned by daemon or driver, but 359 1.1 agc * replace a "list is empty" code by an "ID not found" code, exit. 360 1.1 agc * 361 1.1 agc * Parameters: 362 1.1 agc * n Status code. 363 1.1 agc * 364 1.1 agc * Does not return. 365 1.1 agc */ 366 1.1 agc 367 1.1 agc void 368 1.1 agc status_error_slist(unsigned n) 369 1.1 agc { 370 1.1 agc if (n == ISCSI_STATUS_LIST_EMPTY || n == ISCSID_STATUS_LIST_EMPTY) 371 1.1 agc n = ISCSI_STATUS_INVALID_ID; 372 1.1 agc status_error (n); 373 1.1 agc } 374 1.1 agc 375 1.1 agc 376 1.1 agc /* 377 1.1 agc * get_response: 378 1.1 agc * Read the response from the daemon. 379 1.1 agc * 380 1.1 agc * Parameters: 381 1.1 agc * temp If TRUE, the response is dynamically allocated (so it is not 382 1.1 agc * overwritten by further requests or responses). 383 1.1 agc * 384 1.1 agc * Returns: 385 1.1 agc * Pointer to the response. 386 1.1 agc * 387 1.1 agc * Notes: 388 1.1 agc * This routine allocates an extra integer to mark whether the returned 389 1.1 agc * buffer is dynamic or static. This marker is one int before the 390 1.1 agc * returned pointer. 391 1.1 agc */ 392 1.1 agc 393 1.1 agc iscsid_response_t * 394 1.1 agc get_response(int temp) 395 1.1 agc { 396 1.3 christos ssize_t ret; 397 1.3 christos size_t len; 398 1.1 agc iscsid_response_t *rsp; 399 1.1 agc int *pbuf; 400 1.1 agc 401 1.3 christos pbuf = (int *)(void *)buf; 402 1.3 christos rsp = (iscsid_response_t *)(void *)&pbuf[1]; 403 1.1 agc *pbuf = 0; 404 1.1 agc 405 1.1 agc /* get size of response */ 406 1.1 agc len = sizeof(iscsid_response_t); 407 1.1 agc ret = recv(sock, rsp, len, MSG_PEEK | MSG_WAITALL); 408 1.3 christos if ((size_t)ret != len) 409 1.1 agc io_error("Receiving daemon data"); 410 1.1 agc 411 1.1 agc len += rsp->parameter_length; 412 1.1 agc 413 1.1 agc /* 414 1.1 agc if a temp buffer has been requested, or if the response is too large 415 1.1 agc to fit into the static buffer, alloc a temp buffer. 416 1.1 agc */ 417 1.1 agc 418 1.1 agc temp = temp || (len > (int)(sizeof(buf) - sizeof(int))); 419 1.1 agc 420 1.1 agc if (temp) { 421 1.1 agc if (NULL == (pbuf = (int *) malloc(len + sizeof(int)))) 422 1.2 christos gen_error("Can't allocate response buffer (%zu bytes)", 423 1.1 agc len + sizeof(int)); 424 1.1 agc 425 1.3 christos rsp = (iscsid_response_t *)(void *)&pbuf[1]; 426 1.1 agc *pbuf = 1; 427 1.1 agc } 428 1.1 agc /* get the complete response */ 429 1.1 agc 430 1.1 agc ret = recv(sock, rsp, len, MSG_WAITALL); 431 1.3 christos if ((size_t)ret != len) 432 1.1 agc io_error("Receiving daemon data"); 433 1.1 agc 434 1.1 agc return rsp; 435 1.1 agc } 436 1.1 agc 437 1.1 agc 438 1.1 agc /* 439 1.1 agc * free_response: 440 1.1 agc * If the response buffer was dynamically allocated, free it. 441 1.1 agc * 442 1.1 agc * Parameters: 443 1.1 agc * rsp The response buffer. 444 1.1 agc * The dynamic allocation marker is the int preceding 445 1.1 agc * this address. 446 1.1 agc */ 447 1.1 agc 448 1.1 agc void 449 1.1 agc free_response(iscsid_response_t * rsp) 450 1.1 agc { 451 1.1 agc int *pbuf; 452 1.1 agc 453 1.3 christos pbuf = ((int *)(void *)rsp) - 1; 454 1.1 agc if (*pbuf) 455 1.1 agc free(pbuf); 456 1.1 agc } 457 1.1 agc 458 1.1 agc 459 1.1 agc /* 460 1.1 agc * send_request: 461 1.1 agc * Send a request to the daemon. 462 1.1 agc * 463 1.1 agc * Parameters: 464 1.1 agc * request The request code. 465 1.1 agc * par_len The parameter length. 466 1.1 agc * par The parameter. 467 1.1 agc */ 468 1.1 agc 469 1.1 agc void 470 1.3 christos send_request(unsigned request, size_t par_len, void *par) 471 1.1 agc { 472 1.1 agc iscsid_request_t *req; 473 1.3 christos size_t len; 474 1.3 christos ssize_t ret; 475 1.3 christos int req_temp; 476 1.1 agc 477 1.1 agc len = sizeof(iscsid_request_t) + par_len; 478 1.1 agc 479 1.1 agc /* alloc buffer if static one is too small to hold request */ 480 1.3 christos req_temp = len > sizeof(buf); 481 1.1 agc 482 1.1 agc if (req_temp) { 483 1.1 agc req = malloc(len); 484 1.1 agc if (req == NULL) 485 1.3 christos gen_error("Out of memory allocating %zu bytes\n", len); 486 1.1 agc } else 487 1.3 christos req = (iscsid_request_t *)(void *)buf; 488 1.1 agc 489 1.1 agc /* setup request */ 490 1.1 agc req->request = request; 491 1.3 christos req->parameter_length = (uint32_t)par_len; 492 1.1 agc if (par_len) 493 1.1 agc memcpy(req->parameter, par, par_len); 494 1.1 agc 495 1.1 agc /* and send it out */ 496 1.3 christos ret = sendto(sock, req, len, 0, (struct sockaddr *)(void *)&daemon_name, 497 1.3 christos (socklen_t)sizeof(struct sockaddr_un)); 498 1.3 christos if ((size_t)ret != len) { 499 1.1 agc io_error("Sending daemon message"); 500 1.1 agc } 501 1.1 agc if (req_temp) 502 1.1 agc free(req); 503 1.1 agc } 504 1.1 agc 505 1.1 agc 506 1.1 agc /* 507 1.1 agc * main: 508 1.1 agc * check command, init driver handle and socket, dispatch command. 509 1.1 agc * 510 1.1 agc * Parameter: argc, argv - passed on to commands with offset of 2, so 511 1.1 agc * argv [0] is first argument after command verb. 512 1.1 agc * 513 1.1 agc * Returns: 514 1.1 agc * Whatever the command handler returns, which is currently always 0. 515 1.1 agc */ 516 1.1 agc 517 1.1 agc int 518 1.1 agc main(int argc, char **argv) 519 1.1 agc { 520 1.1 agc command_t *c; 521 1.1 agc int res; 522 1.1 agc int i; 523 1.1 agc 524 1.1 agc (void) snprintf(sockdir, sizeof(sockdir), "/tmp/iscsictl.XXXXXX"); 525 1.1 agc while ((i = getopt(argc, argv, "d:")) != -1) { 526 1.1 agc switch(i) { 527 1.1 agc case 'd': 528 1.1 agc (void) snprintf(sockdir, sizeof(sockdir), "%s", optarg); 529 1.1 agc break; 530 1.1 agc default: 531 1.1 agc break; 532 1.1 agc } 533 1.1 agc } 534 1.1 agc if (argc - optind < 1) { 535 1.1 agc errx(EXIT_FAILURE, "Usage: %s <command> <options>, see manual for details.", 536 1.1 agc progname); 537 1.1 agc } 538 1.1 agc 539 1.1 agc cmdname = argv[optind]; 540 1.1 agc 541 1.1 agc for (c = cmds; c->cmd != NULL; c++) { 542 1.1 agc if (strcmp(c->cmd, cmdname) == 0) { 543 1.1 agc break; 544 1.1 agc } 545 1.1 agc } 546 1.1 agc if (c->cmd == NULL) { 547 1.1 agc errx(EXIT_FAILURE, "Unknown command: '%s'", cmdname); 548 1.1 agc } 549 1.6 joerg if ((driver = open(DEVICE, O_RDONLY)) < 0) 550 1.6 joerg err(EXIT_FAILURE, "Opening " DEVICE); 551 1.1 agc 552 1.1 agc sock = socket(AF_UNIX, SOCK_DGRAM, 0); 553 1.1 agc if (sock < 0) 554 1.1 agc err(EXIT_FAILURE, "opening datagram socket"); 555 1.1 agc 556 1.1 agc /* bind socket to unique name */ 557 1.1 agc if (mkdtemp(sockdir) == NULL) { 558 1.1 agc errx(EXIT_FAILURE, "can't create iscsictl dir '%s'", sockdir); 559 1.1 agc } 560 1.1 agc myname.sun_family = AF_UNIX; 561 1.1 agc (void) snprintf(myname.sun_path, sizeof(myname.sun_path), "%s/socket", sockdir); 562 1.3 christos if (bind(sock, (struct sockaddr *)(void *)&myname, 563 1.3 christos (socklen_t)sizeof(struct sockaddr_un)) < 0) { 564 1.1 agc io_error("Binding name to datagram socket"); 565 1.1 agc } 566 1.1 agc daemon_name.sun_family = AF_UNIX; 567 1.1 agc strlcpy(daemon_name.sun_path, ISCSID_SOCK_NAME, 568 1.1 agc sizeof(daemon_name.sun_path)); 569 1.1 agc 570 1.1 agc /* dispatch command */ 571 1.5 agc res = (*c->proc)(argc - optind - 1, &argv[optind + 1]); 572 1.1 agc 573 1.1 agc /* cleanup */ 574 1.1 agc close(sock); 575 1.1 agc unlink(myname.sun_path); 576 1.1 agc rmdir(sockdir); 577 1.1 agc 578 1.1 agc return res; 579 1.1 agc } 580