#include "iscsic_globals.h"
#include <ctype.h>
#include <assert.h>
STATIC void
get_address(iscsi_portal_address_t * portal, char *str, char *arg)
{
char *sp;
int val;
if (!str || !*str)
arg_error(arg, "Address is missing");
sp = strrchr(str, ',');
if (sp != NULL) {
if (sscanf(sp + 1, "%d", &val) != 1)
arg_error(arg, "Bad address format: Expected group tag");
if (val < 0 || val > 0xffff)
arg_error(arg, "Bad address format: Group tag out of range");
portal->group_tag = (uint16_t) val;
*sp = '\0';
}
sp = strchr(str, ']');
if (sp != NULL)
sp++;
else
sp = str;
sp = strchr(sp, ':');
if (sp != NULL) {
if (strchr(sp + 1, ':') != NULL) {
portal->port = 0;
} else {
if (sscanf(sp + 1, "%d", &val) != 1)
arg_error(arg, "Bad address format: Expected port number");
if (val < 0 || val > 0xffff)
arg_error(arg, "Bad address format: Port number ut of range");
portal->port = (uint16_t) val;
*sp = '\0';
}
}
if (*str == '[') {
sp = strchr(str, ']');
if (sp != NULL && !*(sp+1)) {
str = str + 1;
*sp = '\0';
}
}
if (strlen(str) >= sizeof(portal->address))
arg_error(arg, "Bad address format: Address string too long");
strlcpy((char *)portal->address, str, sizeof(portal->address));
}
STATIC uint16_t
get_short_int(char *sp, char *arg, const char *name)
{
int val;
if (!sp || !*sp)
arg_error(arg, "%s is missing", name);
if (!sscanf(sp, "%d", &val))
arg_error(arg, "Expected integer %s", name);
if (val < 0 || val > 0xffff)
arg_error(arg, "%s out of range", name);
return (uint16_t) val;
}
STATIC uint32_t
get_dsl(char *sp, char *arg)
{
int val;
if (!sp || !*sp)
arg_error(arg, "Missing MaxRecvDataSegmentLength");
if (!sscanf(sp, "%d", &val))
arg_error(arg, "Integer MaxRecvDataSegmentLength expected");
if (val < 512 || val > 0xffffff)
arg_error(arg, "MaxRecvDataSegmentLength out of range");
return (uint32_t) val;
}
STATIC void
get_str(char *dest, char *sp, char *arg, const char *name)
{
if (!sp || !*sp)
arg_error(arg, "%s is missing", name);
if (strlen(sp) >= ISCSI_STRING_LENGTH)
arg_error(arg, "%s is too long", name);
strlcpy(dest, sp, ISCSI_STRING_LENGTH);
}
int
cl_get_target(iscsid_add_target_req_t ** ptarg, int argc, char **argv, int nreq)
{
iscsid_add_target_req_t *targ;
char *sp;
size_t num, len, name;
int i, p;
for (i = (int)(num = name = 0); i < argc; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == 'a')
num++;
if (argv[i][1] == 'n')
name++;
}
if (!name && nreq)
return 0;
len = sizeof(iscsid_add_target_req_t) +
num * sizeof(iscsi_portal_address_t);
if (NULL == (targ = calloc(1, len)))
gen_error("Can't allocate %zu bytes of memory", len);
*ptarg = targ;
p = -1;
for (i = 0; i < argc; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
switch (argv[i][1]) {
case 'n':
get_str((char *)targ->TargetName, sp, argv[i], "Target name");
break;
case 'a':
get_address(&targ->portal[++p], sp, argv[i]);
break;
case 'p':
assert(p >= 0);
targ->portal[p].port = get_short_int(sp, argv[i], "Port");
break;
case 'g':
assert(p >= 0);
targ->portal[p].group_tag = get_short_int(sp, argv[i],
"Group tag");
break;
default:
continue;
}
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
}
targ->num_portals = p + 1;
return (int)len;
}
int
cl_get_isns(iscsid_add_isns_server_req_t * srv, int argc, char **argv)
{
iscsi_portal_address_t addr;
char *sp;
int i, found;
(void) memset(&addr, 0x0, sizeof(addr));
found = FALSE;
for (i = 0; i < argc; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
switch (argv[i][1]) {
case 'N':
get_str((char *)srv->name, sp, argv[i], "Server name");
break;
case 'a':
get_address(&addr, sp, argv[i]);
found = TRUE;
break;
case 'p':
addr.port = get_short_int(sp, argv[i], "Port");
break;
default:
continue;
}
if (!argv[i][2]) {
argv[i + 1] = NULL;
}
argv[i] = NULL;
}
strlcpy((char *)srv->address, (char *)addr.address, sizeof(srv->address));
srv->port = addr.port;
return found;
}
int
cl_get_auth_opts(iscsid_set_target_authentication_req_t *auth,
int argc, char **argv)
{
int n, i, found;
char *sp;
found = FALSE;
memset(auth, 0, sizeof(*auth));
for (i = 0; i < argc; i++) {
if (!argv[i] || argv[i][0] != '-') {
continue;
}
sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
switch (argv[i][1]) {
case 't':
if (!sp || !*sp)
arg_error(argv[i], "Missing authentication type");
n = 0;
while (*sp) {
switch (*sp) {
case 'n':
auth->auth_info.auth_type[n] = ISCSI_AUTH_None;
break;
case 'c':
auth->auth_info.auth_type[n] = ISCSI_AUTH_CHAP;
break;
case 'C':
auth->auth_info.auth_type[n] = ISCSI_AUTH_CHAP;
auth->auth_info.mutual_auth = 1;
break;
default:
arg_error(argv[i], "Bad authentication type '%c'", *sp);
}
sp++;
n++;
}
auth->auth_info.auth_number = n;
break;
case 'u':
get_str((char *)auth->user_name, sp, argv[i], "User name");
break;
case 's':
get_str((char *)auth->password, sp, argv[i], "Secret");
break;
case 'S':
get_str((char *)auth->target_password, sp, argv[i], "Target secret");
break;
default:
continue;
}
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
return found;
}
int
cl_get_target_opts(iscsid_get_set_target_options_t * opt, int argc, char **argv)
{
int i, found;
char *sp;
found = FALSE;
memset(opt, 0, sizeof(*opt));
for (i = 0; i < argc; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
switch (argv[i][1]) {
case 'h':
opt->HeaderDigest = ISCSI_DIGEST_CRC32C;
opt->is_present.HeaderDigest = 1;
break;
case 'd':
opt->DataDigest = ISCSI_DIGEST_CRC32C;
opt->is_present.DataDigest = 1;
break;
case 'w':
opt->DefaultTime2Wait = get_short_int(sp, argv[i], "Time to wait");
opt->is_present.DefaultTime2Wait = 1;
if (!argv[i][2])
argv[i + 1] = NULL;
break;
case 'r':
opt->DefaultTime2Retain = get_short_int(sp, argv[i],
"Time to retain");
opt->is_present.DefaultTime2Retain = 1;
if (!argv[i][2])
argv[i + 1] = NULL;
break;
case 'e':
opt->ErrorRecoveryLevel = get_short_int(sp, argv[i],
"ErrorRecoveryLevel");
opt->is_present.ErrorRecoveryLevel = 1;
if (!argv[i][2])
argv[i + 1] = NULL;
break;
case 'l':
opt->MaxRecvDataSegmentLength = get_dsl(sp, argv[i]);
opt->is_present.MaxRecvDataSegmentLength = 1;
if (!argv[i][2])
argv[i + 1] = NULL;
break;
default:
continue;
}
argv[i] = NULL;
found = TRUE;
}
return found;
}
int
cl_get_portal(iscsid_add_portal_req_t * port, int argc, char **argv)
{
char *sp;
int i, found;
iscsid_portal_options_t *opt = &port->options;
found = FALSE;
memset(port, 0, sizeof(*port));
for (i = 0; i < argc; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
switch (argv[i][1]) {
case 'a':
get_address(&port->portal, sp, argv[i]);
found = TRUE;
break;
case 'p':
port->portal.port = get_short_int(sp, argv[i], "Port");
break;
case 'g':
port->portal.group_tag = get_short_int(sp, argv[i], "Group tag");
break;
case 'h':
opt->HeaderDigest = ISCSI_DIGEST_CRC32C;
opt->is_present.HeaderDigest = 1;
break;
case 'd':
opt->DataDigest = ISCSI_DIGEST_CRC32C;
opt->is_present.DataDigest = 1;
break;
case 'l':
opt->MaxRecvDataSegmentLength = get_dsl(sp, argv[i]);
opt->is_present.MaxRecvDataSegmentLength = 1;
if (!argv[i][2])
argv[i + 1] = NULL;
break;
default:
continue;
}
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
}
return found;
}
int
cl_get_id(char ident, iscsid_sym_id_t * sid, int argc, char **argv)
{
int i, found;
char *sp;
found = FALSE;
memset(sid, 0, sizeof(*sid));
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2] :
((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Missing ID");
if (strlen(sp) >= ISCSI_STRING_LENGTH)
arg_error(argv[i], "ID String too long");
if (!sscanf(sp, "%d", &sid->id))
strlcpy((char *)sid->name, sp, sizeof(sid->name));
else if (!sid->id)
arg_error(argv[i], "Invalid ID");
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return found;
}
int
cl_get_symname(uint8_t * sn, int argc, char **argv)
{
int i, found;
char *sp;
found = FALSE;
*sn = '\0';
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == 'N') {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Symbolic name missing");
if (isdigit((unsigned char)*sp))
arg_error(argv[i], "Symbolic name must not be numeric");
if (strlen(sp) >= ISCSI_STRING_LENGTH)
arg_error(argv[i], "Symbolic name too long");
strlcpy((char *)sn, sp, ISCSI_STRING_LENGTH);
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return found;
}
int
cl_get_string(char ident, char *pstr, int argc, char **argv)
{
int i, found;
char *sp;
found = FALSE;
*pstr = '\0';
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
get_str(pstr, sp, argv[i], "String");
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return found;
}
int
cl_get_opt(char ident, int argc, char **argv)
{
int i, found;
found = FALSE;
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
argv[i] = NULL;
found = TRUE;
}
}
return found;
}
char
cl_get_char(char ident, int argc, char **argv)
{
int i, found;
char *sp;
char ch = 0;
found = FALSE;
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Option character missing");
if (strlen(sp) > 1)
arg_error(argv[i], "Option invalid");
ch = *sp;
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return ch;
}
int
cl_get_int(char ident, int argc, char **argv)
{
int i, found;
char *sp;
int val = 0;
found = FALSE;
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Option value missing");
if (!sscanf(sp, "%i", &val))
arg_error(argv[i], "Integer expected");
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return val;
}
#if 0
int
cl_get_uint(char ident, int argc, char **argv)
{
int i, found;
char *sp;
int val = -1;
found = FALSE;
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Option value missing");
if (!sscanf(sp, "%i", &val))
arg_error(argv[i], "Positive integer expected");
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return val;
}
#endif
uint64_t
cl_get_longlong(char ident, int argc, char **argv)
{
int i, found;
char *sp;
uint64_t val = 0;
found = FALSE;
for (i = 0; i < argc && !found; i++) {
if (!argv[i] || argv[i][0] != '-')
continue;
if (argv[i][1] == ident) {
sp = (argv[i][2]) ? &argv[i][2]
: ((i + 1 < argc) ? argv[i + 1] : NULL);
if (!sp || !*sp)
arg_error(argv[i], "Option value missing");
if (!sscanf(sp, "%qi", (long long *)(void *)&val))
arg_error(argv[i], "Integer expected");
if (!argv[i][2])
argv[i + 1] = NULL;
argv[i] = NULL;
found = TRUE;
}
}
return val;
}