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
get_address(iscsi_portal_address_t * portal,char * str,char * arg)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
get_short_int(char * sp,char * arg,const char * name)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
get_dsl(char * sp,char * arg)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
get_str(char * dest,char * sp,char * arg,const char * name)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
cl_get_target(iscsid_add_target_req_t ** ptarg,int argc,char ** argv,int nreq)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
cl_get_isns(iscsid_add_isns_server_req_t * srv,int argc,char ** argv)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
cl_get_auth_opts(iscsid_set_target_authentication_req_t * auth,int argc,char ** argv)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
cl_get_target_opts(iscsid_get_set_target_options_t * opt,int argc,char ** argv)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
cl_get_portal(iscsid_add_portal_req_t * port,int argc,char ** argv)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
cl_get_id(char ident,iscsid_sym_id_t * sid,int argc,char ** argv)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
cl_get_symname(uint8_t * sn,int argc,char ** argv)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
cl_get_string(char ident,char * pstr,int argc,char ** argv)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
cl_get_opt(char ident,int argc,char ** argv)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
cl_get_char(char ident,int argc,char ** argv)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
cl_get_int(char ident,int argc,char ** argv)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
cl_get_longlong(char ident,int argc,char ** argv)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