Home | History | Annotate | Line # | Download | only in iscsictl
      1 /*	$NetBSD: iscsic_parse.c,v 1.5 2023/11/25 08:06:02 mlelstv Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Wasabi Systems, Inc.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "iscsic_globals.h"
     33 
     34 #include <ctype.h>
     35 #include <assert.h>
     36 
     37 /*
     38  * get_address:
     39  *    Get an address specification that may include port and group tag.
     40  *
     41  *    Parameter:
     42  *       portal   The portal address
     43  *       str      The parameter string to scan
     44  *
     45  *    Aborts app on error.
     46  */
     47 
     48 STATIC void
     49 get_address(iscsi_portal_address_t * portal, char *str, char *arg)
     50 {
     51 	char *sp;
     52 	int val;
     53 
     54 	if (!str || !*str)
     55 		arg_error(arg, "Address is missing");
     56 
     57 	/* Parse and strip trailing group tag */
     58 	sp = strrchr(str, ',');
     59 	if (sp != NULL) {
     60 		if (sscanf(sp + 1, "%d", &val) != 1)
     61 			arg_error(arg, "Bad address format: Expected group tag");
     62 		if (val < 0 || val > 0xffff)
     63 			arg_error(arg, "Bad address format: Group tag out of range");
     64 		portal->group_tag = (uint16_t) val;
     65 		*sp = '\0';
     66 	}
     67 
     68 	/* Skip over bracketed IPv6 address */
     69 	sp = strchr(str, ']');
     70 	if (sp != NULL)
     71 		sp++;
     72 	else
     73 		sp = str;
     74 
     75 	/* Parse and strip trailing port number */
     76 	sp = strchr(sp, ':');
     77 	if (sp != NULL) {
     78 		if (strchr(sp + 1, ':') != NULL) {
     79 			/*
     80 			 *  If there's a second colon, assume
     81 			 *  it's an unbracketed IPv6 address
     82 			 */
     83 			portal->port = 0;
     84 		} else {
     85 			if (sscanf(sp + 1, "%d", &val) != 1)
     86 				arg_error(arg, "Bad address format: Expected port number");
     87 			if (val < 0 || val > 0xffff)
     88 				arg_error(arg, "Bad address format: Port number ut  of range");
     89 			portal->port = (uint16_t) val;
     90 			*sp = '\0';
     91 		}
     92 	}
     93 
     94 	/* Remove brackets */
     95 	if (*str == '[') {
     96 		sp = strchr(str, ']');
     97 		if (sp != NULL && !*(sp+1)) {
     98 			str = str + 1;
     99 			*sp = '\0';
    100 		}
    101 	}
    102 
    103 	/*
    104 	 * only check length, don't verify correct format
    105 	 * (too many possibilities)
    106 	 */
    107 	if (strlen(str) >= sizeof(portal->address))
    108 		arg_error(arg, "Bad address format: Address string too long");
    109 
    110 	strlcpy((char *)portal->address, str, sizeof(portal->address));
    111 }
    112 
    113 
    114 
    115 /*
    116  * get_short_int:
    117  *    Get a short integer.
    118  *
    119  *    Parameter:
    120  *       sp       The parameter string to scan
    121  *       arg      The associated option argument (for error message)
    122  *       name     The argument name
    123  *
    124  *    Returns given integer, aborts app on error.
    125  */
    126 
    127 STATIC uint16_t
    128 get_short_int(char *sp, char *arg, const char *name)
    129 {
    130 	int val;
    131 
    132 	if (!sp || !*sp)
    133 		arg_error(arg, "%s is missing", name);
    134 
    135 	if (!sscanf(sp, "%d", &val))
    136 		arg_error(arg, "Expected integer %s", name);
    137 	if (val < 0 || val > 0xffff)
    138 		arg_error(arg, "%s out of range", name);
    139 
    140 	return (uint16_t) val;
    141 }
    142 
    143 
    144 /*
    145  * get_dsl:
    146  *    Get MaxRecvDataSegmentLength
    147  *
    148  *    Parameter:
    149  *       sp       The parameter string to scan
    150  *       arg      The associated option argument (for error message)
    151  *
    152  *    Returns given integer, aborts app on error.
    153  */
    154 
    155 STATIC uint32_t
    156 get_dsl(char *sp, char *arg)
    157 {
    158 	int val;
    159 
    160 	if (!sp || !*sp)
    161 		arg_error(arg, "Missing MaxRecvDataSegmentLength");
    162 	if (!sscanf(sp, "%d", &val))
    163 		arg_error(arg, "Integer MaxRecvDataSegmentLength expected");
    164 	if (val < 512 || val > 0xffffff)
    165 		arg_error(arg, "MaxRecvDataSegmentLength out of range");
    166 
    167 	return (uint32_t) val;
    168 }
    169 
    170 
    171 /*
    172  * get_str:
    173  *    Get a string.
    174  *
    175  *    Parameter:
    176  *       dest     The destination string
    177  *       sp       The parameter string to scan
    178  *       arg      The associated option argument (for error message)
    179  *       name     The argument name
    180  *
    181  *    Aborts app on error.
    182  */
    183 
    184 STATIC void
    185 get_str(char *dest, char *sp, char *arg, const char *name)
    186 {
    187 
    188 	if (!sp || !*sp)
    189 		arg_error(arg, "%s is missing", name);
    190 	if (strlen(sp) >= ISCSI_STRING_LENGTH)
    191 		arg_error(arg, "%s is too long", name);
    192 
    193 	strlcpy(dest, sp, ISCSI_STRING_LENGTH);
    194 }
    195 
    196 /*
    197  * cl_get_target:
    198  *    Get a target address specification that may include name, address, port,
    199  *    and group tag, with address/port/tag possibly repeated.
    200  *
    201  *    Parameter:
    202  *       ptarg       pointer to hold the resulting add target request parameter
    203  *       argc, argv  program parameters (shifted)
    204  *       nreq        target name is required if TRUE
    205  *
    206  *    Returns:    0 if there is no target, else the size of the allocated
    207  *                  request.
    208  *                Aborts app on bad parameter or mem allocation error.
    209  */
    210 
    211 int
    212 cl_get_target(iscsid_add_target_req_t ** ptarg, int argc, char **argv, int nreq)
    213 {
    214 	iscsid_add_target_req_t *targ;
    215 	char *sp;
    216 	size_t num, len, name;
    217 	int i, p;
    218 
    219 	/* count number of addresses first, so we know how much memory to allocate */
    220 	for (i = (int)(num = name = 0); i < argc; i++) {
    221 		if (!argv[i] || argv[i][0] != '-')
    222 			continue;
    223 		if (argv[i][1] == 'a')
    224 			num++;
    225 		if (argv[i][1] == 'n')
    226 			name++;
    227 	}
    228 
    229 	if (!name && nreq)
    230 		return 0;
    231 
    232 	len = sizeof(iscsid_add_target_req_t) +
    233 		num * sizeof(iscsi_portal_address_t);
    234 
    235 	if (NULL == (targ = calloc(1, len)))
    236 		gen_error("Can't allocate %zu bytes of memory", len);
    237 
    238 	*ptarg = targ;
    239 	p = -1;
    240 
    241 	for (i = 0; i < argc; i++) {
    242 		if (!argv[i] || argv[i][0] != '-')
    243 			continue;
    244 
    245 		sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
    246 
    247 		switch (argv[i][1]) {
    248 		case 'n':				/* target name */
    249 			get_str((char *)targ->TargetName, sp, argv[i], "Target name");
    250 			break;
    251 
    252 		case 'a':				/* target address */
    253 			get_address(&targ->portal[++p], sp, argv[i]);
    254 			break;
    255 
    256 		case 'p':				/* port */
    257 			assert(p >= 0);
    258 			targ->portal[p].port = get_short_int(sp, argv[i], "Port");
    259 			break;
    260 
    261 		case 'g':				/* group tag */
    262 			assert(p >= 0);
    263 			targ->portal[p].group_tag = get_short_int(sp, argv[i],
    264 														"Group tag");
    265 			break;
    266 
    267 		default:
    268 			continue;
    269 		}
    270 		if (!argv[i][2])
    271 			argv[i + 1] = NULL;
    272 
    273 		argv[i] = NULL;
    274 	}
    275 	targ->num_portals = p + 1;
    276 
    277 	return (int)len;
    278 }
    279 
    280 
    281 /*
    282  * cl_get_isns:
    283  *    Get an iSNS server address specification that may include name, address
    284  *    and port.
    285  *
    286  *    Parameter:
    287  *       srv         add_isns_server request parameter
    288  *       argc, argv  program parameters (shifted)
    289  *
    290  *    Returns:    0 on error, 1 if OK.
    291  */
    292 
    293 int
    294 cl_get_isns(iscsid_add_isns_server_req_t * srv, int argc, char **argv)
    295 {
    296 	iscsi_portal_address_t addr;
    297 	char *sp;
    298 	int i, found;
    299 
    300 	(void) memset(&addr, 0x0, sizeof(addr));
    301 	found = FALSE;
    302 
    303 	for (i = 0; i < argc; i++) {
    304 		if (!argv[i] || argv[i][0] != '-')
    305 			continue;
    306 
    307 		sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
    308 
    309 		switch (argv[i][1]) {
    310 		case 'N':				/* symbolic name */
    311 			get_str((char *)srv->name, sp, argv[i], "Server name");
    312 			break;
    313 
    314 		case 'a':				/* target address */
    315 			get_address(&addr, sp, argv[i]);
    316 			found = TRUE;
    317 			break;
    318 
    319 		case 'p':				/* port */
    320 			addr.port = get_short_int(sp, argv[i], "Port");
    321 			break;
    322 
    323 		default:
    324 			continue;
    325 		}
    326 		if (!argv[i][2]) {
    327 			argv[i + 1] = NULL;
    328 		}
    329 		argv[i] = NULL;
    330 	}
    331 
    332 	strlcpy((char *)srv->address, (char *)addr.address, sizeof(srv->address));
    333 	srv->port = addr.port;
    334 
    335 	return found;
    336 }
    337 
    338 
    339 /*
    340  * cl_get_auth_opts:
    341  *    Get authentication options.
    342  *
    343  *    Parameter:
    344  *          auth        authentication parameters
    345  *          argc, argv  program parameters (shifted)
    346  *
    347  *    Returns:    0 if there are no authorization options, 1 otherwise.
    348  *                Aborts app on bad parameter.
    349  */
    350 
    351 int
    352 cl_get_auth_opts(iscsid_set_target_authentication_req_t *auth,
    353 				 int argc, char **argv)
    354 {
    355 	int n, i, found;
    356 	char *sp;
    357 
    358 	found = FALSE;
    359 	memset(auth, 0, sizeof(*auth));
    360 
    361 	for (i = 0; i < argc; i++) {
    362 		if (!argv[i] || argv[i][0] != '-') {
    363 			continue;
    364 		}
    365 		sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
    366 
    367 		switch (argv[i][1]) {
    368 		case 't':				/* authentication type */
    369 			if (!sp || !*sp)
    370 				arg_error(argv[i], "Missing authentication type");
    371 			n = 0;
    372 			while (*sp) {
    373 				switch (*sp) {
    374 				case 'n':		/* no authentication */
    375 					auth->auth_info.auth_type[n] = ISCSI_AUTH_None;
    376 					break;
    377 				case 'c':		/* CHAP authentication */
    378 					auth->auth_info.auth_type[n] = ISCSI_AUTH_CHAP;
    379 					break;
    380 				case 'C':		/* Mutual CHAP authentication */
    381 					auth->auth_info.auth_type[n] = ISCSI_AUTH_CHAP;
    382 					auth->auth_info.mutual_auth = 1;
    383 					break;
    384 				default:
    385 					arg_error(argv[i], "Bad authentication type '%c'", *sp);
    386 				}
    387 				sp++;
    388 				n++;
    389 			}
    390 			auth->auth_info.auth_number = n;
    391 			break;
    392 
    393 		case 'u':				/* user name */
    394 			get_str((char *)auth->user_name, sp, argv[i], "User name");
    395 			break;
    396 
    397 		case 's':				/* secret */
    398 			get_str((char *)auth->password, sp, argv[i], "Secret");
    399 			break;
    400 
    401 		case 'S':				/* target secret */
    402 			get_str((char *)auth->target_password, sp, argv[i], "Target secret");
    403 			break;
    404 
    405 		default:
    406 			continue;
    407 		}
    408 		if (!argv[i][2])
    409 			argv[i + 1] = NULL;
    410 
    411 		argv[i] = NULL;
    412 		found = TRUE;
    413 	}
    414 	return found;
    415 }
    416 
    417 
    418 /*
    419  * cl_get_target_opts:
    420  *    Get session/connection options.
    421  *
    422  *    Parameter:
    423  *          opt         target options
    424  *          argc, argv  program parameters (shifted)
    425  *
    426  *    Returns:    0 if there are no target options, 1 otherwise.
    427  *                Aborts app on bad parameter.
    428  */
    429 
    430 int
    431 cl_get_target_opts(iscsid_get_set_target_options_t * opt, int argc, char **argv)
    432 {
    433 	int i, found;
    434 	char *sp;
    435 
    436 	found = FALSE;
    437 	memset(opt, 0, sizeof(*opt));
    438 
    439 	for (i = 0; i < argc; i++) {
    440 		if (!argv[i] || argv[i][0] != '-')
    441 			continue;
    442 
    443 		sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
    444 
    445 		switch (argv[i][1]) {
    446 		case 'h':				/* Header Digest */
    447 			opt->HeaderDigest = ISCSI_DIGEST_CRC32C;
    448 			opt->is_present.HeaderDigest = 1;
    449 			break;
    450 
    451 		case 'd':				/* Data Digest */
    452 			opt->DataDigest = ISCSI_DIGEST_CRC32C;
    453 			opt->is_present.DataDigest = 1;
    454 			break;
    455 
    456 		case 'w':				/* Time 2 Wait */
    457 			opt->DefaultTime2Wait = get_short_int(sp, argv[i], "Time to wait");
    458 			opt->is_present.DefaultTime2Wait = 1;
    459 			if (!argv[i][2])
    460 				argv[i + 1] = NULL;
    461 			break;
    462 
    463 		case 'r':				/* Time 2 Retain */
    464 			opt->DefaultTime2Retain = get_short_int(sp, argv[i],
    465 													"Time to retain");
    466 			opt->is_present.DefaultTime2Retain = 1;
    467 			if (!argv[i][2])
    468 				argv[i + 1] = NULL;
    469 			break;
    470 
    471 		case 'e':				/* Error Recovery Level */
    472 			opt->ErrorRecoveryLevel = get_short_int(sp, argv[i],
    473 													"ErrorRecoveryLevel");
    474 			opt->is_present.ErrorRecoveryLevel = 1;
    475 			if (!argv[i][2])
    476 				argv[i + 1] = NULL;
    477 			break;
    478 
    479 		case 'l':				/* Data Segment Length */
    480 			opt->MaxRecvDataSegmentLength = get_dsl(sp, argv[i]);
    481 			opt->is_present.MaxRecvDataSegmentLength = 1;
    482 			if (!argv[i][2])
    483 				argv[i + 1] = NULL;
    484 			break;
    485 
    486 		default:
    487 			continue;
    488 		}
    489 		argv[i] = NULL;
    490 		found = TRUE;
    491 	}
    492 	return found;
    493 }
    494 
    495 
    496 /*
    497  * cl_get_portal:
    498  *    Get a portal address specification that may include address, port,
    499  *    and group tag, plus portal options.
    500  *
    501  *    Parameter:
    502  *          port        add portal request parameter
    503  *          argc, argv  program parameters (shifted)
    504  *
    505  *    Returns:    FALSE if there is no portal, else TRUE.
    506  *                Aborts app on bad parameter or mem allocation error.
    507  */
    508 
    509 int
    510 cl_get_portal(iscsid_add_portal_req_t * port, int argc, char **argv)
    511 {
    512 	char *sp;
    513 	int i, found;
    514 	iscsid_portal_options_t *opt = &port->options;
    515 
    516 	found = FALSE;
    517 	memset(port, 0, sizeof(*port));
    518 
    519 	for (i = 0; i < argc; i++) {
    520 		if (!argv[i] || argv[i][0] != '-')
    521 			continue;
    522 
    523 		sp = (argv[i][2]) ? &argv[i][2] : ((i + 1 < argc) ? argv[i + 1] : NULL);
    524 
    525 		switch (argv[i][1]) {
    526 		case 'a':				/* target address */
    527 			get_address(&port->portal, sp, argv[i]);
    528 			found = TRUE;
    529 			break;
    530 
    531 		case 'p':				/* port */
    532 			port->portal.port = get_short_int(sp, argv[i], "Port");
    533 			break;
    534 
    535 		case 'g':				/* group tag */
    536 			port->portal.group_tag = get_short_int(sp, argv[i], "Group tag");
    537 			break;
    538 
    539 		case 'h':				/* Header Digest */
    540 			opt->HeaderDigest = ISCSI_DIGEST_CRC32C;
    541 			opt->is_present.HeaderDigest = 1;
    542 			break;
    543 
    544 		case 'd':				/* Data Digest */
    545 			opt->DataDigest = ISCSI_DIGEST_CRC32C;
    546 			opt->is_present.DataDigest = 1;
    547 			break;
    548 
    549 		case 'l':				/* Data Segment Length */
    550 			opt->MaxRecvDataSegmentLength = get_dsl(sp, argv[i]);
    551 			opt->is_present.MaxRecvDataSegmentLength = 1;
    552 			if (!argv[i][2])
    553 				argv[i + 1] = NULL;
    554 			break;
    555 
    556 		default:
    557 			continue;
    558 		}
    559 		if (!argv[i][2])
    560 			argv[i + 1] = NULL;
    561 
    562 		argv[i] = NULL;
    563 	}
    564 	return found;
    565 }
    566 
    567 
    568 /*
    569  * cl_get_id:
    570  *    Get an identifier (symbolic or numeric)
    571  *
    572  *    Parameter:
    573  *          ident       the parameter identifier character
    574  *          sid         the ID
    575  *          argc, argv  program parameters (shifted)
    576  *
    577  *    Returns:    0 if there is no ID, 1 otherwise.
    578  *                Aborts app on bad parameter.
    579  */
    580 
    581 int
    582 cl_get_id(char ident, iscsid_sym_id_t * sid, int argc, char **argv)
    583 {
    584 	int i, found;
    585 	char *sp;
    586 
    587 	found = FALSE;
    588 	memset(sid, 0, sizeof(*sid));
    589 
    590 	for (i = 0; i < argc && !found; i++) {
    591 		if (!argv[i] || argv[i][0] != '-')
    592 			continue;
    593 
    594 		if (argv[i][1] == ident) {
    595 			sp = (argv[i][2]) ? &argv[i][2] :
    596 				((i + 1 < argc) ? argv[i + 1] : NULL);
    597 
    598 			if (!sp || !*sp)
    599 				arg_error(argv[i], "Missing ID");
    600 			if (strlen(sp) >= ISCSI_STRING_LENGTH)
    601 				arg_error(argv[i], "ID String too long");
    602 			if (!sscanf(sp, "%d", &sid->id))
    603 				strlcpy((char *)sid->name, sp, sizeof(sid->name));
    604 			else if (!sid->id)
    605 				arg_error(argv[i], "Invalid ID");
    606 
    607 			if (!argv[i][2])
    608 				argv[i + 1] = NULL;
    609 
    610 			argv[i] = NULL;
    611 			found = TRUE;
    612 		}
    613 	}
    614 	return found;
    615 }
    616 
    617 
    618 /*
    619  * cl_get_symname:
    620  *    Get a symbolic name
    621  *
    622  *    Parameter:
    623  *          sn          the name
    624  *          argc, argv  program parameters (shifted)
    625  *
    626  *    Returns:    0 if there is no symbolic name, 1 otherwise.
    627  *                Aborts app on bad parameter.
    628  */
    629 
    630 int
    631 cl_get_symname(uint8_t * sn, int argc, char **argv)
    632 {
    633 	int i, found;
    634 	char *sp;
    635 
    636 	found = FALSE;
    637 	*sn = '\0';
    638 
    639 	for (i = 0; i < argc && !found; i++) {
    640 		if (!argv[i] || argv[i][0] != '-')
    641 			continue;
    642 
    643 		if (argv[i][1] == 'N') {
    644 			sp = (argv[i][2]) ? &argv[i][2]
    645 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    646 
    647 			if (!sp || !*sp)
    648 				arg_error(argv[i], "Symbolic name missing");
    649 			if (isdigit((unsigned char)*sp))
    650 				arg_error(argv[i], "Symbolic name must not be numeric");
    651 			if (strlen(sp) >= ISCSI_STRING_LENGTH)
    652 				arg_error(argv[i], "Symbolic name too long");
    653 
    654 			strlcpy((char *)sn, sp, ISCSI_STRING_LENGTH);
    655 
    656 			if (!argv[i][2])
    657 				argv[i + 1] = NULL;
    658 
    659 			argv[i] = NULL;
    660 			found = TRUE;
    661 		}
    662 	}
    663 	return found;
    664 }
    665 
    666 
    667 /*
    668  * cl_get_string:
    669  *    Get a string value
    670  *
    671  *    Parameter:
    672  *          ident       the parameter identifier character
    673  *          pstr        the result string
    674  *          argc, argv  program parameters (shifted)
    675  *
    676  *    Returns:    0 if there is no string, 1 otherwise.
    677  *                Aborts app on bad parameter.
    678  */
    679 
    680 int
    681 cl_get_string(char ident, char *pstr, int argc, char **argv)
    682 {
    683 	int i, found;
    684 	char *sp;
    685 
    686 	found = FALSE;
    687 	*pstr = '\0';
    688 
    689 	for (i = 0; i < argc && !found; i++) {
    690 		if (!argv[i] || argv[i][0] != '-')
    691 			continue;
    692 
    693 		if (argv[i][1] == ident) {
    694 			sp = (argv[i][2]) ? &argv[i][2]
    695 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    696 
    697 			get_str(pstr, sp, argv[i], "String");
    698 
    699 			if (!argv[i][2])
    700 				argv[i + 1] = NULL;
    701 
    702 			argv[i] = NULL;
    703 			found = TRUE;
    704 		}
    705 	}
    706 	return found;
    707 }
    708 
    709 
    710 /*
    711  * cl_get_opt:
    712  *    Get an option with no value
    713  *
    714  *    Parameter:
    715  *          ident       the parameter identifier character
    716  *          argc, argv  program parameters (shifted)
    717  *
    718  *    Returns:    0 if the option was not found, 1 otherwise.
    719  *                Aborts app on bad parameter.
    720  */
    721 
    722 int
    723 cl_get_opt(char ident, int argc, char **argv)
    724 {
    725 	int i, found;
    726 
    727 	found = FALSE;
    728 
    729 	for (i = 0; i < argc && !found; i++) {
    730 		if (!argv[i] || argv[i][0] != '-')
    731 			continue;
    732 
    733 		if (argv[i][1] == ident) {
    734 			argv[i] = NULL;
    735 			found = TRUE;
    736 		}
    737 	}
    738 	return found;
    739 }
    740 
    741 
    742 /*
    743  * cl_get_char:
    744  *    Get an option with a character value
    745  *
    746  *    Parameter:
    747  *          ident       the parameter identifier character
    748  *          argc, argv  program parameters (shifted)
    749  *
    750  *    Returns:    The option character (0 if not found).
    751  *                Aborts app on bad parameter.
    752  */
    753 
    754 char
    755 cl_get_char(char ident, int argc, char **argv)
    756 {
    757 	int i, found;
    758 	char *sp;
    759 	char ch = 0;
    760 
    761 	found = FALSE;
    762 
    763 	for (i = 0; i < argc && !found; i++) {
    764 		if (!argv[i] || argv[i][0] != '-')
    765 			continue;
    766 
    767 		if (argv[i][1] == ident) {
    768 			sp = (argv[i][2]) ? &argv[i][2]
    769 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    770 
    771 			if (!sp || !*sp)
    772 				arg_error(argv[i], "Option character missing");
    773 			if (strlen(sp) > 1)
    774 				arg_error(argv[i], "Option invalid");
    775 			ch = *sp;
    776 
    777 			if (!argv[i][2])
    778 				argv[i + 1] = NULL;
    779 
    780 			argv[i] = NULL;
    781 			found = TRUE;
    782 		}
    783 	}
    784 
    785 	return ch;
    786 }
    787 
    788 
    789 /*
    790  * cl_get_int:
    791  *    Get an option with an integer value
    792  *
    793  *    Parameter:
    794  *          ident       the parameter identifier character
    795  *          argc, argv  program parameters (shifted)
    796  *
    797  *    Returns:    The option value (0 if not found).
    798  *                Aborts app on bad parameter.
    799  */
    800 
    801 int
    802 cl_get_int(char ident, int argc, char **argv)
    803 {
    804 	int i, found;
    805 	char *sp;
    806 	int val = 0;
    807 
    808 	found = FALSE;
    809 
    810 	for (i = 0; i < argc && !found; i++) {
    811 		if (!argv[i] || argv[i][0] != '-')
    812 			continue;
    813 
    814 		if (argv[i][1] == ident) {
    815 			sp = (argv[i][2]) ? &argv[i][2]
    816 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    817 
    818 			if (!sp || !*sp)
    819 				arg_error(argv[i], "Option value missing");
    820 			if (!sscanf(sp, "%i", &val))
    821 				arg_error(argv[i], "Integer expected");
    822 
    823 			if (!argv[i][2])
    824 				argv[i + 1] = NULL;
    825 
    826 			argv[i] = NULL;
    827 			found = TRUE;
    828 		}
    829 	}
    830 
    831 	return val;
    832 }
    833 
    834 
    835 /*
    836  * cl_get_uint:
    837  *    Get an option with a positive integer value
    838  *
    839  *    Parameter:
    840  *          ident       the parameter identifier character
    841  *          argc, argv  program parameters (shifted)
    842  *
    843  *    Returns:    The option value (-1 if not found).
    844  *                Aborts app on bad parameter.
    845  */
    846 
    847 #if 0
    848 int
    849 cl_get_uint(char ident, int argc, char **argv)
    850 {
    851 	int i, found;
    852 	char *sp;
    853 	int val = -1;
    854 
    855 	found = FALSE;
    856 
    857 	for (i = 0; i < argc && !found; i++) {
    858 		if (!argv[i] || argv[i][0] != '-')
    859 			continue;
    860 
    861 		if (argv[i][1] == ident) {
    862 			sp = (argv[i][2]) ? &argv[i][2]
    863 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    864 
    865 			if (!sp || !*sp)
    866 				arg_error(argv[i], "Option value missing");
    867 			if (!sscanf(sp, "%i", &val))
    868 				arg_error(argv[i], "Positive integer expected");
    869 
    870 			if (!argv[i][2])
    871 				argv[i + 1] = NULL;
    872 
    873 			argv[i] = NULL;
    874 			found = TRUE;
    875 		}
    876 	}
    877 
    878 	return val;
    879 }
    880 #endif
    881 
    882 
    883 /*
    884  * cl_get_longlong:
    885  *    Get an option with a 64-bit value
    886  *
    887  *    Parameter:
    888  *          ident       the parameter identifier character
    889  *          argc, argv  program parameters (shifted)
    890  *
    891  *    Returns:    The option value (0 if not found).
    892  *                Aborts app on bad parameter.
    893  */
    894 
    895 uint64_t
    896 cl_get_longlong(char ident, int argc, char **argv)
    897 {
    898 	int i, found;
    899 	char *sp;
    900 	uint64_t val = 0;
    901 
    902 	found = FALSE;
    903 
    904 	for (i = 0; i < argc && !found; i++) {
    905 		if (!argv[i] || argv[i][0] != '-')
    906 			continue;
    907 
    908 		if (argv[i][1] == ident) {
    909 			sp = (argv[i][2]) ? &argv[i][2]
    910 				: ((i + 1 < argc) ? argv[i + 1] : NULL);
    911 
    912 			if (!sp || !*sp)
    913 				arg_error(argv[i], "Option value missing");
    914 			if (!sscanf(sp, "%qi", (long long *)(void *)&val))
    915 				arg_error(argv[i], "Integer expected");
    916 
    917 			if (!argv[i][2])
    918 				argv[i + 1] = NULL;
    919 
    920 			argv[i] = NULL;
    921 			found = TRUE;
    922 		}
    923 	}
    924 
    925 	return val;
    926 }
    927