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