1*44f0e146Sjoerg /* $NetBSD: iscsic_main.c,v 1.6 2015/05/30 15:57:32 joerg Exp $ */
275a17f3cSagc
375a17f3cSagc /*-
475a17f3cSagc * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
575a17f3cSagc * All rights reserved.
675a17f3cSagc *
775a17f3cSagc * This code is derived from software contributed to The NetBSD Foundation
875a17f3cSagc * by Wasabi Systems, Inc.
975a17f3cSagc *
1075a17f3cSagc * Redistribution and use in source and binary forms, with or without
1175a17f3cSagc * modification, are permitted provided that the following conditions
1275a17f3cSagc * are met:
1375a17f3cSagc * 1. Redistributions of source code must retain the above copyright
1475a17f3cSagc * notice, this list of conditions and the following disclaimer.
1575a17f3cSagc * 2. Redistributions in binary form must reproduce the above copyright
1675a17f3cSagc * notice, this list of conditions and the following disclaimer in the
1775a17f3cSagc * documentation and/or other materials provided with the distribution.
1875a17f3cSagc *
1975a17f3cSagc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2075a17f3cSagc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2175a17f3cSagc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2275a17f3cSagc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2375a17f3cSagc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2475a17f3cSagc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2575a17f3cSagc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2675a17f3cSagc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2775a17f3cSagc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2875a17f3cSagc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2975a17f3cSagc * POSSIBILITY OF SUCH DAMAGE.
3075a17f3cSagc */
3175a17f3cSagc #include <sys/types.h>
3275a17f3cSagc #include <sys/param.h>
3375a17f3cSagc #include <sys/socket.h>
3475a17f3cSagc #include <sys/un.h>
3575a17f3cSagc
3675a17f3cSagc #include "iscsic_globals.h"
3775a17f3cSagc
3875a17f3cSagc #include <err.h>
3975a17f3cSagc #include <errno.h>
4075a17f3cSagc #include <fcntl.h>
4175a17f3cSagc #include <stdarg.h>
4275a17f3cSagc
4375a17f3cSagc #define DEVICE "/dev/iscsi0"
4475a17f3cSagc
4575a17f3cSagc #define ISCSICTL_VERSION "20110805"
4675a17f3cSagc
4775a17f3cSagc /*
4875a17f3cSagc *-------- Table of commands and the associated handler function -------------
4975a17f3cSagc */
5075a17f3cSagc
5175a17f3cSagc static command_t cmds[] = {
5275a17f3cSagc {"version", get_version},
5375a17f3cSagc {"add_target", add_target},
5475a17f3cSagc {"add_portal", add_portal},
5575a17f3cSagc {"remove_target", remove_target},
5675a17f3cSagc {"slp_find_targets", slp_find_targets},
5775a17f3cSagc {"refresh_targets", refresh_targets},
5875a17f3cSagc {"list_targets", list_targets},
5975a17f3cSagc {"add_send_target", add_send_target},
6075a17f3cSagc {"remove_send_target", remove_send_target},
6175a17f3cSagc {"list_send_targets", list_send_targets},
6275a17f3cSagc {"add_isns_server", add_isns_server},
6375a17f3cSagc {"remove_isns_server", remove_isns_server},
6475a17f3cSagc {"find_isns_servers", find_isns_servers},
6575a17f3cSagc {"list_isns_servers", list_isns_servers},
6675a17f3cSagc {"refresh_isns", refresh_isns},
6775a17f3cSagc {"login", login},
6875a17f3cSagc {"logout", logout},
6975a17f3cSagc {"add_connection", add_connection},
7075a17f3cSagc {"remove_connection", remove_connection},
7175a17f3cSagc {"inquiry", inquiry},
7275a17f3cSagc {"read_capacity", read_capacity},
7375a17f3cSagc {"report_luns", report_luns},
7475a17f3cSagc {"test_unit_ready", test_unit_ready},
7575a17f3cSagc {"add_initiator", add_initiator},
7675a17f3cSagc {"remove_initiator", remove_initiator},
7775a17f3cSagc {"list_initiators", list_initiators},
7875a17f3cSagc {"list_sessions", list_sessions},
7975a17f3cSagc {"set_node_name", set_node_name},
8075a17f3cSagc {NULL, NULL}
8175a17f3cSagc };
8275a17f3cSagc
8375a17f3cSagc
8475a17f3cSagc /*
8575a17f3cSagc *-------- Table of error codes and the associated message text -------------
8675a17f3cSagc */
8775a17f3cSagc
8875a17f3cSagc typedef struct {
8975a17f3cSagc unsigned code;
9075a17f3cSagc const char *str;
9175a17f3cSagc } status_msg_t;
9275a17f3cSagc
9375a17f3cSagc static status_msg_t status_msg[] = {
9475a17f3cSagc {ISCSI_STATUS_LIST_EMPTY, "The list is empty"},
9575a17f3cSagc {ISCSI_STATUS_DUPLICATE_NAME, "The specified name is not unique"},
9675a17f3cSagc {ISCSI_STATUS_GENERAL_ERROR, "A non-specific error occurred"},
9775a17f3cSagc {ISCSI_STATUS_LOGIN_FAILED, "The login failed"},
9875a17f3cSagc {ISCSI_STATUS_CONNECTION_FAILED, "The attempt to establish a connection failed"},
9975a17f3cSagc {ISCSI_STATUS_AUTHENTICATION_FAILED, "Authentication negotiation failed"},
10075a17f3cSagc {ISCSI_STATUS_NO_RESOURCES, "Could not allocate resources (e.g. memory)"},
10175a17f3cSagc {ISCSI_STATUS_MAXED_CONNECTIONS, "Maximum number of connections exceeded"},
10275a17f3cSagc {ISCSI_STATUS_INVALID_SESSION_ID, "Session ID not found"},
10375a17f3cSagc {ISCSI_STATUS_INVALID_CONNECTION_ID, "Connection ID not found"},
10475a17f3cSagc {ISCSI_STATUS_INVALID_SOCKET, "Specified socket is invalid"},
10575a17f3cSagc {ISCSI_STATUS_NOTIMPL, "Feature not implemented"},
10675a17f3cSagc {ISCSI_STATUS_CHECK_CONDITION, "Target reported CHECK CONDITION"},
10775a17f3cSagc {ISCSI_STATUS_TARGET_BUSY, "Target reported BUSY"},
10875a17f3cSagc {ISCSI_STATUS_TARGET_ERROR, "Target reported other error"},
10975a17f3cSagc {ISCSI_STATUS_TARGET_FAILURE, "Command Response was Target Failure"},
11075a17f3cSagc {ISCSI_STATUS_TARGET_DROP, "Target dropped connection"},
11175a17f3cSagc {ISCSI_STATUS_SOCKET_ERROR, "Communication failure"},
11275a17f3cSagc {ISCSI_STATUS_PARAMETER_MISSING, "A required ioctl parameter is missing"},
11375a17f3cSagc {ISCSI_STATUS_PARAMETER_INVALID, "A parameter is malformed (string too long etc.)"},
11475a17f3cSagc {ISCSI_STATUS_MAP_FAILED, "Mapping the LUNs failed"},
11575a17f3cSagc {ISCSI_STATUS_NO_INITIATOR_NAME, "Initiator name not set"},
11675a17f3cSagc {ISCSI_STATUS_NEGOTIATION_ERROR, "Negotiation failure (invalid key or value)"},
11775a17f3cSagc {ISCSI_STATUS_TIMEOUT, "Command timed out (at iSCSI level)"},
11875a17f3cSagc {ISCSI_STATUS_PROTOCOL_ERROR, "Internal Error (Protocol error reject)"},
11975a17f3cSagc {ISCSI_STATUS_PDU_ERROR, "Internal Error (Invalid PDU field reject)"},
12075a17f3cSagc {ISCSI_STATUS_CMD_NOT_SUPPORTED, "Target does not support iSCSI command"},
12175a17f3cSagc {ISCSI_STATUS_DRIVER_UNLOAD, "Driver is unloading"},
12275a17f3cSagc {ISCSI_STATUS_LOGOUT, "Session was logged out"},
12375a17f3cSagc {ISCSI_STATUS_PDUS_LOST, "Excessive PDU loss"},
12475a17f3cSagc {ISCSI_STATUS_INVALID_EVENT_ID, "Invalid Event ID"},
12575a17f3cSagc {ISCSI_STATUS_EVENT_DEREGISTERED, "Wait for event cancelled by deregistration"},
12675a17f3cSagc {ISCSI_STATUS_EVENT_WAITING, "Already waiting for event"},
12775a17f3cSagc {ISCSI_STATUS_TASK_NOT_FOUND, "Task Management: task not found"},
12875a17f3cSagc {ISCSI_STATUS_LUN_NOT_FOUND, "Task Management: LUN not found"},
12975a17f3cSagc {ISCSI_STATUS_TASK_ALLEGIANT, "Task Management: Task still allegiant"},
13075a17f3cSagc {ISCSI_STATUS_CANT_REASSIGN, "Task Management: Task reassignment not supported"},
13175a17f3cSagc {ISCSI_STATUS_FUNCTION_UNSUPPORTED, "Task Management: Function unsupported"},
13275a17f3cSagc {ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED, "Task Management: Function not authorized"},
13375a17f3cSagc {ISCSI_STATUS_FUNCTION_REJECTED, "Task Management: Function rejected"},
13475a17f3cSagc {ISCSI_STATUS_UNKNOWN_REASON, "Task Management: Unknown reason code"},
13575a17f3cSagc {ISCSI_STATUS_DUPLICATE_ID, "Duplicate ID"},
13675a17f3cSagc {ISCSI_STATUS_INVALID_ID, "ID not found"},
13775a17f3cSagc {ISCSI_STATUS_TARGET_LOGOUT, "Target requested logout"},
13875a17f3cSagc {ISCSI_STATUS_LOGOUT_CID_NOT_FOUND, "Logout error: Connection ID not found"},
13975a17f3cSagc {ISCSI_STATUS_LOGOUT_RECOVERY_NS, "Logout error: Recovery not supported"},
14075a17f3cSagc {ISCSI_STATUS_LOGOUT_ERROR, "Logout error: Unknown reason"},
14175a17f3cSagc
14275a17f3cSagc {ISCSID_STATUS_LIST_EMPTY, "The list is empty"},
14375a17f3cSagc {ISCSID_STATUS_DUPLICATE_NAME, "The specified name is not unique"},
14475a17f3cSagc {ISCSID_STATUS_GENERAL_ERROR, "A non-specific error occurred"},
14575a17f3cSagc {ISCSID_STATUS_CONNECT_ERROR, "Failed to connect to target"},
14675a17f3cSagc {ISCSID_STATUS_NO_RESOURCES, "Could not allocate resources (e.g. memory)"},
14775a17f3cSagc {ISCSID_STATUS_INVALID_SESSION_ID, "Session ID not found"},
14875a17f3cSagc {ISCSID_STATUS_INVALID_CONNECTION_ID, "Connection ID not found"},
14975a17f3cSagc {ISCSID_STATUS_NOTIMPL, "Feature not implemented"},
15075a17f3cSagc {ISCSID_STATUS_SOCKET_ERROR, "Failed to create socket"},
15175a17f3cSagc {ISCSID_STATUS_PARAMETER_MISSING, "A required parameter is missing"},
15275a17f3cSagc {ISCSID_STATUS_PARAMETER_INVALID, "Request parameter is invalid"},
15375a17f3cSagc {ISCSID_STATUS_NO_INITIATOR_NAME, "Initiator name was not set"},
15475a17f3cSagc {ISCSID_STATUS_TIMEOUT, "Request timed out"},
15575a17f3cSagc {ISCSID_STATUS_DRIVER_NOT_LOADED, "iSCSI Driver not loaded"},
15675a17f3cSagc {ISCSID_STATUS_INVALID_REQUEST, "Unknown request code"},
15775a17f3cSagc {ISCSID_STATUS_INVALID_PORTAL_ID, "Portal ID not found"},
15875a17f3cSagc {ISCSID_STATUS_INVALID_TARGET_ID, "Target ID not found"},
15975a17f3cSagc {ISCSID_STATUS_NOT_FOUND, "Requested item not found"},
16075a17f3cSagc {ISCSID_STATUS_HOST_NOT_FOUND, "Target address not found"},
16175a17f3cSagc {ISCSID_STATUS_HOST_TRY_AGAIN, "Target address retrieval failed, try again later"},
16275a17f3cSagc {ISCSID_STATUS_HOST_ERROR, "Target address invalid"},
16375a17f3cSagc {ISCSID_STATUS_NO_TARGETS_FOUND, "No targets found"},
16475a17f3cSagc {ISCSID_STATUS_INVALID_ISNS_ID, "iSNS ID not found"},
16575a17f3cSagc {ISCSID_STATUS_ISNS_ERROR, "Problem connecting to iSNS"},
16675a17f3cSagc {ISCSID_STATUS_ISNS_SERVER_ERROR, "iSNS server returned garbage"},
16775a17f3cSagc {ISCSID_STATUS_DUPLICATE_ENTRY, "The entry already exists"},
16875a17f3cSagc {ISCSID_STATUS_INVALID_INITIATOR_ID, "Initiator ID not found"},
16975a17f3cSagc {ISCSID_STATUS_INITIATOR_BIND_ERROR, "Bind to initiator portal failed"},
17075a17f3cSagc
17175a17f3cSagc {0, NULL}
17275a17f3cSagc };
17375a17f3cSagc
17475a17f3cSagc /* -------------------------------------------------------------------------- */
17575a17f3cSagc /* local variables */
17675a17f3cSagc
17775a17f3cSagc static struct sockaddr_un daemon_name; /* daemon socket name */
17875a17f3cSagc
17975a17f3cSagc static char sockdir[MAXPATHLEN]; /* where myname lives */
18075a17f3cSagc static struct sockaddr_un myname; /* my socket name */
18175a17f3cSagc static int sock; /* the socket */
18275a17f3cSagc
18375a17f3cSagc static char *cmdname; /* pointer to command name for error msgs */
18475a17f3cSagc
18575a17f3cSagc /* global variables */
18675a17f3cSagc
18775a17f3cSagc uint8_t buf[BUF_SIZE]; /* buffer for daemon comm and driver I/O */
18875a17f3cSagc
18975a17f3cSagc int driver; /* driver handle */
19075a17f3cSagc
19175a17f3cSagc /* -------------------------------------------------------------------------- */
19275a17f3cSagc
19375a17f3cSagc #define progname getprogname()
19475a17f3cSagc
19575a17f3cSagc
19675a17f3cSagc /*
19775a17f3cSagc * bye:
19875a17f3cSagc * Cleanup and exit. Does not return.
19975a17f3cSagc */
20075a17f3cSagc
201549f044eSjoerg __dead static void
bye(void)20275a17f3cSagc bye(void)
20375a17f3cSagc {
20475a17f3cSagc close(sock);
20575a17f3cSagc (void) unlink(myname.sun_path);
20675a17f3cSagc (void) rmdir(sockdir);
20775a17f3cSagc exit(EXIT_FAILURE);
20875a17f3cSagc }
20975a17f3cSagc
21075a17f3cSagc
21175a17f3cSagc /*
21275a17f3cSagc * arg_error:
21375a17f3cSagc * Display error message about an invalid argument, exit.
21475a17f3cSagc *
21575a17f3cSagc * Parameters:
21675a17f3cSagc * argp Argument value
21775a17f3cSagc * fmt Error message
21875a17f3cSagc * ... additional output arguments
21975a17f3cSagc *
22075a17f3cSagc * Does not return.
22175a17f3cSagc */
22275a17f3cSagc
22375a17f3cSagc void
arg_error(char * argp,const char * fmt,...)22475a17f3cSagc arg_error(char *argp, const char *fmt, ...)
22575a17f3cSagc {
22675a17f3cSagc va_list args;
22775a17f3cSagc char lbuf[BUF_SIZE];
22875a17f3cSagc
22975a17f3cSagc va_start(args, fmt);
23075a17f3cSagc vsnprintf(lbuf, sizeof(lbuf), fmt, args);
23175a17f3cSagc fprintf(stderr, "%s: %s: Invalid option at or near '%s': %s\n",
23275a17f3cSagc progname, cmdname, argp, lbuf);
23375a17f3cSagc bye();
23475a17f3cSagc }
23575a17f3cSagc
23675a17f3cSagc
23775a17f3cSagc /*
23875a17f3cSagc * arg_missing:
23975a17f3cSagc * Display error message about a missing argument, exit.
24075a17f3cSagc *
24175a17f3cSagc * Parameters:
24275a17f3cSagc * arg Argument name
24375a17f3cSagc *
24475a17f3cSagc * Does not return.
24575a17f3cSagc */
24675a17f3cSagc
24775a17f3cSagc void
arg_missing(const char * arg)24875a17f3cSagc arg_missing(const char *arg)
24975a17f3cSagc {
25075a17f3cSagc warnx("%s: Missing argument: %s", cmdname, arg);
25175a17f3cSagc bye();
25275a17f3cSagc }
25375a17f3cSagc
25475a17f3cSagc
25575a17f3cSagc /*
25675a17f3cSagc * io_error:
25775a17f3cSagc * Display error message about an I/O error (includes system error code)
25875a17f3cSagc *
25975a17f3cSagc * Parameters:
26075a17f3cSagc * fmt format string
26175a17f3cSagc * ... additional output arguments
26275a17f3cSagc *
26375a17f3cSagc * Does not return.
26475a17f3cSagc */
26575a17f3cSagc
26675a17f3cSagc void
io_error(const char * fmt,...)26775a17f3cSagc io_error(const char *fmt, ...)
26875a17f3cSagc {
26975a17f3cSagc va_list args;
27075a17f3cSagc char lbuf[BUF_SIZE];
27175a17f3cSagc
27275a17f3cSagc va_start(args, fmt);
27375a17f3cSagc vsnprintf(lbuf, sizeof(lbuf), fmt, args);
27475a17f3cSagc fprintf(stderr, "%s: %s: %s: %s\n",
27575a17f3cSagc progname, cmdname, lbuf, strerror(errno));
27675a17f3cSagc bye();
27775a17f3cSagc }
27875a17f3cSagc
27975a17f3cSagc
28075a17f3cSagc /*
28175a17f3cSagc * gen_error:
28275a17f3cSagc * Display general error message.
28375a17f3cSagc *
28475a17f3cSagc * Parameters:
28575a17f3cSagc * fmt format string
28675a17f3cSagc * ... additional output arguments
28775a17f3cSagc *
28875a17f3cSagc * Does not return.
28975a17f3cSagc */
29075a17f3cSagc
29175a17f3cSagc void
gen_error(const char * fmt,...)29275a17f3cSagc gen_error(const char *fmt, ...)
29375a17f3cSagc {
29475a17f3cSagc va_list args;
29575a17f3cSagc char lbuf[BUF_SIZE];
29675a17f3cSagc
29775a17f3cSagc va_start(args, fmt);
29875a17f3cSagc vsnprintf(lbuf, sizeof(lbuf), fmt, args);
29975a17f3cSagc fprintf(stderr, "%s: %s: %s\n", progname, cmdname, lbuf);
30075a17f3cSagc bye();
30175a17f3cSagc }
30275a17f3cSagc
30375a17f3cSagc
30475a17f3cSagc /*
30575a17f3cSagc * check_extra_args:
30675a17f3cSagc * Display error message & exit if there is an unrecognized argument.
30775a17f3cSagc *
30875a17f3cSagc * Parameters:
30975a17f3cSagc * argc Argument count
31075a17f3cSagc * argv Argument value array.
31175a17f3cSagc *
31275a17f3cSagc * Does not return if an extra arg is found.
31375a17f3cSagc */
31475a17f3cSagc
31575a17f3cSagc void
check_extra_args(int argc,char ** argv)31675a17f3cSagc check_extra_args(int argc, char **argv)
31775a17f3cSagc {
31875a17f3cSagc int i;
31975a17f3cSagc
32075a17f3cSagc for (i = 0; i < argc; i++)
32175a17f3cSagc if (argv[i] != NULL) {
32275a17f3cSagc warnx("%s: Unrecognized argument '%s'", cmdname, argv[i]);
32375a17f3cSagc bye();
32475a17f3cSagc }
32575a17f3cSagc }
32675a17f3cSagc
32775a17f3cSagc
32875a17f3cSagc /*
32975a17f3cSagc * status_error:
33075a17f3cSagc * Display error message for status returned by daemon or driver, exit.
33175a17f3cSagc *
33275a17f3cSagc * Parameters:
33375a17f3cSagc * n Status code.
33475a17f3cSagc *
33575a17f3cSagc * Does not return.
33675a17f3cSagc */
33775a17f3cSagc
33875a17f3cSagc void
status_error(unsigned n)33975a17f3cSagc status_error(unsigned n)
34075a17f3cSagc {
34175a17f3cSagc int i;
34275a17f3cSagc
34375a17f3cSagc for (i = 0; status_msg[i].code; i++)
34475a17f3cSagc if (status_msg[i].code == n)
34575a17f3cSagc break;
34675a17f3cSagc
34775a17f3cSagc if (status_msg[i].code)
34875a17f3cSagc warnx("%s: %s", cmdname, status_msg[i].str);
34975a17f3cSagc else
35075a17f3cSagc warnx("%s: Undefined error code %d", cmdname, n);
35175a17f3cSagc
35275a17f3cSagc bye();
35375a17f3cSagc }
35475a17f3cSagc
35575a17f3cSagc
35675a17f3cSagc /*
35775a17f3cSagc * status_error_slist:
35875a17f3cSagc * Display error message for status returned by daemon or driver, but
35975a17f3cSagc * replace a "list is empty" code by an "ID not found" code, exit.
36075a17f3cSagc *
36175a17f3cSagc * Parameters:
36275a17f3cSagc * n Status code.
36375a17f3cSagc *
36475a17f3cSagc * Does not return.
36575a17f3cSagc */
36675a17f3cSagc
36775a17f3cSagc void
status_error_slist(unsigned n)36875a17f3cSagc status_error_slist(unsigned n)
36975a17f3cSagc {
37075a17f3cSagc if (n == ISCSI_STATUS_LIST_EMPTY || n == ISCSID_STATUS_LIST_EMPTY)
37175a17f3cSagc n = ISCSI_STATUS_INVALID_ID;
37275a17f3cSagc status_error (n);
37375a17f3cSagc }
37475a17f3cSagc
37575a17f3cSagc
37675a17f3cSagc /*
37775a17f3cSagc * get_response:
37875a17f3cSagc * Read the response from the daemon.
37975a17f3cSagc *
38075a17f3cSagc * Parameters:
38175a17f3cSagc * temp If TRUE, the response is dynamically allocated (so it is not
38275a17f3cSagc * overwritten by further requests or responses).
38375a17f3cSagc *
38475a17f3cSagc * Returns:
38575a17f3cSagc * Pointer to the response.
38675a17f3cSagc *
38775a17f3cSagc * Notes:
38875a17f3cSagc * This routine allocates an extra integer to mark whether the returned
38975a17f3cSagc * buffer is dynamic or static. This marker is one int before the
39075a17f3cSagc * returned pointer.
39175a17f3cSagc */
39275a17f3cSagc
39375a17f3cSagc iscsid_response_t *
get_response(int temp)39475a17f3cSagc get_response(int temp)
39575a17f3cSagc {
3961309a94fSchristos ssize_t ret;
3971309a94fSchristos size_t len;
39875a17f3cSagc iscsid_response_t *rsp;
39975a17f3cSagc int *pbuf;
40075a17f3cSagc
4011309a94fSchristos pbuf = (int *)(void *)buf;
4021309a94fSchristos rsp = (iscsid_response_t *)(void *)&pbuf[1];
40375a17f3cSagc *pbuf = 0;
40475a17f3cSagc
40575a17f3cSagc /* get size of response */
40675a17f3cSagc len = sizeof(iscsid_response_t);
40775a17f3cSagc ret = recv(sock, rsp, len, MSG_PEEK | MSG_WAITALL);
4081309a94fSchristos if ((size_t)ret != len)
40975a17f3cSagc io_error("Receiving daemon data");
41075a17f3cSagc
41175a17f3cSagc len += rsp->parameter_length;
41275a17f3cSagc
41375a17f3cSagc /*
41475a17f3cSagc if a temp buffer has been requested, or if the response is too large
41575a17f3cSagc to fit into the static buffer, alloc a temp buffer.
41675a17f3cSagc */
41775a17f3cSagc
41875a17f3cSagc temp = temp || (len > (int)(sizeof(buf) - sizeof(int)));
41975a17f3cSagc
42075a17f3cSagc if (temp) {
42175a17f3cSagc if (NULL == (pbuf = (int *) malloc(len + sizeof(int))))
4222360984dSchristos gen_error("Can't allocate response buffer (%zu bytes)",
42375a17f3cSagc len + sizeof(int));
42475a17f3cSagc
4251309a94fSchristos rsp = (iscsid_response_t *)(void *)&pbuf[1];
42675a17f3cSagc *pbuf = 1;
42775a17f3cSagc }
42875a17f3cSagc /* get the complete response */
42975a17f3cSagc
43075a17f3cSagc ret = recv(sock, rsp, len, MSG_WAITALL);
4311309a94fSchristos if ((size_t)ret != len)
43275a17f3cSagc io_error("Receiving daemon data");
43375a17f3cSagc
43475a17f3cSagc return rsp;
43575a17f3cSagc }
43675a17f3cSagc
43775a17f3cSagc
43875a17f3cSagc /*
43975a17f3cSagc * free_response:
44075a17f3cSagc * If the response buffer was dynamically allocated, free it.
44175a17f3cSagc *
44275a17f3cSagc * Parameters:
44375a17f3cSagc * rsp The response buffer.
44475a17f3cSagc * The dynamic allocation marker is the int preceding
44575a17f3cSagc * this address.
44675a17f3cSagc */
44775a17f3cSagc
44875a17f3cSagc void
free_response(iscsid_response_t * rsp)44975a17f3cSagc free_response(iscsid_response_t * rsp)
45075a17f3cSagc {
45175a17f3cSagc int *pbuf;
45275a17f3cSagc
4531309a94fSchristos pbuf = ((int *)(void *)rsp) - 1;
45475a17f3cSagc if (*pbuf)
45575a17f3cSagc free(pbuf);
45675a17f3cSagc }
45775a17f3cSagc
45875a17f3cSagc
45975a17f3cSagc /*
46075a17f3cSagc * send_request:
46175a17f3cSagc * Send a request to the daemon.
46275a17f3cSagc *
46375a17f3cSagc * Parameters:
46475a17f3cSagc * request The request code.
46575a17f3cSagc * par_len The parameter length.
46675a17f3cSagc * par The parameter.
46775a17f3cSagc */
46875a17f3cSagc
46975a17f3cSagc void
send_request(unsigned request,size_t par_len,void * par)4701309a94fSchristos send_request(unsigned request, size_t par_len, void *par)
47175a17f3cSagc {
47275a17f3cSagc iscsid_request_t *req;
4731309a94fSchristos size_t len;
4741309a94fSchristos ssize_t ret;
4751309a94fSchristos int req_temp;
47675a17f3cSagc
47775a17f3cSagc len = sizeof(iscsid_request_t) + par_len;
47875a17f3cSagc
47975a17f3cSagc /* alloc buffer if static one is too small to hold request */
4801309a94fSchristos req_temp = len > sizeof(buf);
48175a17f3cSagc
48275a17f3cSagc if (req_temp) {
48375a17f3cSagc req = malloc(len);
48475a17f3cSagc if (req == NULL)
4851309a94fSchristos gen_error("Out of memory allocating %zu bytes\n", len);
48675a17f3cSagc } else
4871309a94fSchristos req = (iscsid_request_t *)(void *)buf;
48875a17f3cSagc
48975a17f3cSagc /* setup request */
49075a17f3cSagc req->request = request;
4911309a94fSchristos req->parameter_length = (uint32_t)par_len;
49275a17f3cSagc if (par_len)
49375a17f3cSagc memcpy(req->parameter, par, par_len);
49475a17f3cSagc
49575a17f3cSagc /* and send it out */
4961309a94fSchristos ret = sendto(sock, req, len, 0, (struct sockaddr *)(void *)&daemon_name,
4971309a94fSchristos (socklen_t)sizeof(struct sockaddr_un));
4981309a94fSchristos if ((size_t)ret != len) {
49975a17f3cSagc io_error("Sending daemon message");
50075a17f3cSagc }
50175a17f3cSagc if (req_temp)
50275a17f3cSagc free(req);
50375a17f3cSagc }
50475a17f3cSagc
50575a17f3cSagc
50675a17f3cSagc /*
50775a17f3cSagc * main:
50875a17f3cSagc * check command, init driver handle and socket, dispatch command.
50975a17f3cSagc *
51075a17f3cSagc * Parameter: argc, argv - passed on to commands with offset of 2, so
51175a17f3cSagc * argv [0] is first argument after command verb.
51275a17f3cSagc *
51375a17f3cSagc * Returns:
51475a17f3cSagc * Whatever the command handler returns, which is currently always 0.
51575a17f3cSagc */
51675a17f3cSagc
51775a17f3cSagc int
main(int argc,char ** argv)51875a17f3cSagc main(int argc, char **argv)
51975a17f3cSagc {
52075a17f3cSagc command_t *c;
52175a17f3cSagc int res;
52275a17f3cSagc int i;
52375a17f3cSagc
52475a17f3cSagc (void) snprintf(sockdir, sizeof(sockdir), "/tmp/iscsictl.XXXXXX");
52575a17f3cSagc while ((i = getopt(argc, argv, "d:")) != -1) {
52675a17f3cSagc switch(i) {
52775a17f3cSagc case 'd':
52875a17f3cSagc (void) snprintf(sockdir, sizeof(sockdir), "%s", optarg);
52975a17f3cSagc break;
53075a17f3cSagc default:
53175a17f3cSagc break;
53275a17f3cSagc }
53375a17f3cSagc }
53475a17f3cSagc if (argc - optind < 1) {
53575a17f3cSagc errx(EXIT_FAILURE, "Usage: %s <command> <options>, see manual for details.",
53675a17f3cSagc progname);
53775a17f3cSagc }
53875a17f3cSagc
53975a17f3cSagc cmdname = argv[optind];
54075a17f3cSagc
54175a17f3cSagc for (c = cmds; c->cmd != NULL; c++) {
54275a17f3cSagc if (strcmp(c->cmd, cmdname) == 0) {
54375a17f3cSagc break;
54475a17f3cSagc }
54575a17f3cSagc }
54675a17f3cSagc if (c->cmd == NULL) {
54775a17f3cSagc errx(EXIT_FAILURE, "Unknown command: '%s'", cmdname);
54875a17f3cSagc }
549*44f0e146Sjoerg if ((driver = open(DEVICE, O_RDONLY)) < 0)
550*44f0e146Sjoerg err(EXIT_FAILURE, "Opening " DEVICE);
55175a17f3cSagc
55275a17f3cSagc sock = socket(AF_UNIX, SOCK_DGRAM, 0);
55375a17f3cSagc if (sock < 0)
55475a17f3cSagc err(EXIT_FAILURE, "opening datagram socket");
55575a17f3cSagc
55675a17f3cSagc /* bind socket to unique name */
55775a17f3cSagc if (mkdtemp(sockdir) == NULL) {
55875a17f3cSagc errx(EXIT_FAILURE, "can't create iscsictl dir '%s'", sockdir);
55975a17f3cSagc }
56075a17f3cSagc myname.sun_family = AF_UNIX;
56175a17f3cSagc (void) snprintf(myname.sun_path, sizeof(myname.sun_path), "%s/socket", sockdir);
5621309a94fSchristos if (bind(sock, (struct sockaddr *)(void *)&myname,
5631309a94fSchristos (socklen_t)sizeof(struct sockaddr_un)) < 0) {
56475a17f3cSagc io_error("Binding name to datagram socket");
56575a17f3cSagc }
56675a17f3cSagc daemon_name.sun_family = AF_UNIX;
56775a17f3cSagc strlcpy(daemon_name.sun_path, ISCSID_SOCK_NAME,
56875a17f3cSagc sizeof(daemon_name.sun_path));
56975a17f3cSagc
57075a17f3cSagc /* dispatch command */
57176ad6f22Sagc res = (*c->proc)(argc - optind - 1, &argv[optind + 1]);
57275a17f3cSagc
57375a17f3cSagc /* cleanup */
57475a17f3cSagc close(sock);
57575a17f3cSagc unlink(myname.sun_path);
57675a17f3cSagc rmdir(sockdir);
57775a17f3cSagc
57875a17f3cSagc return res;
57975a17f3cSagc }
580