]> git.ipfire.org Git - thirdparty/openssl.git/blame - apps/opt.c
Fix typo in error message
[thirdparty/openssl.git] / apps / opt.c
CommitLineData
7e1b7485
RS
1/* ====================================================================
2 * Copyright (c) 2015 The OpenSSL Project. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the OpenSSL Project
19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
20 *
21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * licensing@OpenSSL.org.
25 *
26 * 5. Products derived from this software may not be called "OpenSSL"
27 * nor may "OpenSSL" appear in their names without prior written
28 * permission of the OpenSSL Project.
29 *
30 * 6. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by the OpenSSL Project
33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 */
49
50/* #define COMPILE_STANDALONE_TEST_DRIVER */
51#include "apps.h"
7e1b7485
RS
52#include <string.h>
53#if !defined(OPENSSL_SYS_MSDOS)
54# include OPENSSL_UNISTD
55#endif
a3ed492f 56
7e1b7485
RS
57#include <stdlib.h>
58#include <errno.h>
59#include <ctype.h>
bd4850df 60#include <limits.h>
7e1b7485
RS
61#include <openssl/bio.h>
62
63#define MAX_OPT_HELP_WIDTH 30
64const char OPT_HELP_STR[] = "--";
65const char OPT_MORE_STR[] = "---";
66
67/* Our state */
68static char **argv;
69static int argc;
70static int opt_index;
71static char *arg;
72static char *flag;
73static char *dunno;
74static const OPTIONS *unknown;
75static const OPTIONS *opts;
76static char prog[40];
77
78/*
79 * Return the simple name of the program; removing various platform gunk.
80 */
81#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_NETWARE)
82char *opt_progname(const char *argv0)
83{
45f13518 84 size_t i, n;
7e1b7485
RS
85 const char *p;
86 char *q;
87
88 /* find the last '/', '\' or ':' */
89 for (p = argv0 + strlen(argv0); --p > argv0;)
90 if (*p == '/' || *p == '\\' || *p == ':') {
91 p++;
92 break;
93 }
94
95 /* Strip off trailing nonsense. */
96 n = strlen(p);
97 if (n > 4 &&
a3ed492f 98 (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
7e1b7485
RS
99 n -= 4;
100#if defined(OPENSSL_SYS_NETWARE)
101 if (n > 4 &&
a3ed492f 102 (strcmp(&p[n - 4], ".nlm") == 0 || strcmp(&p[n - 4], ".NLM") == 0))
7e1b7485
RS
103 n -= 4;
104#endif
105
106 /* Copy over the name, in lowercase. */
107 if (n > sizeof prog - 1)
108 n = sizeof prog - 1;
109 for (q = prog, i = 0; i < n; i++, p++)
a3ed492f 110 *q++ = isupper(*p) ? tolower(*p) : *p;
7e1b7485
RS
111 *q = '\0';
112 return prog;
113}
114
115#elif defined(OPENSSL_SYS_VMS)
116
117char *opt_progname(const char *argv0)
118{
119 const char *p, *q;
120
121 /* Find last special charcter sys:[foo.bar]openssl */
122 for (p = argv0 + strlen(argv0); --p > argv0;)
123 if (*p == ':' || *p == ']' || *p == '>') {
124 p++;
125 break;
126 }
127
128 q = strrchr(p, '.');
129 strncpy(prog, p, sizeof prog - 1);
130 prog[sizeof prog - 1] = '\0';
211a68b4 131 if (q != NULL && q - p < sizeof prog)
7e1b7485
RS
132 prog[q - p] = '\0';
133 return prog;
134}
135
136#else
137
138char *opt_progname(const char *argv0)
139{
140 const char *p;
141
142 /* Could use strchr, but this is like the ones above. */
143 for (p = argv0 + strlen(argv0); --p > argv0;)
144 if (*p == '/') {
145 p++;
146 break;
147 }
148 strncpy(prog, p, sizeof prog - 1);
149 prog[sizeof prog - 1] = '\0';
150 return prog;
151}
152#endif
153
154char *opt_getprog(void)
155{
156 return prog;
157}
158
159/* Set up the arg parsing. */
160char *opt_init(int ac, char **av, const OPTIONS *o)
161{
162 /* Store state. */
163 argc = ac;
164 argv = av;
165 opt_index = 1;
166 opts = o;
167 opt_progname(av[0]);
168 unknown = NULL;
169
170 for (; o->name; ++o) {
171 const OPTIONS *next;
172#ifndef NDEBUG
88806cfc 173 int duplicated, i;
7e1b7485
RS
174#endif
175
176 if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR)
177 continue;
178#ifndef NDEBUG
179 i = o->valtype;
180
181 /* Make sure options are legit. */
182 assert(o->name[0] != '-');
183 assert(o->retval > 0);
184 assert(i == 0 || i == '-'
185 || i == 'n' || i == 'p' || i == 'u'
186 || i == 's' || i == '<' || i == '>' || i == '/'
187 || i == 'f' || i == 'F');
188
189 /* Make sure there are no duplicates. */
88806cfc 190 for (next = o + 1; next->name; ++next) {
7e1b7485 191 /*
88806cfc 192 * Some compilers inline strcmp and the assert string is too long.
7e1b7485 193 */
88806cfc
RS
194 duplicated = strcmp(o->name, next->name) == 0;
195 assert(!duplicated);
7e1b7485
RS
196 }
197#endif
198 if (o->name[0] == '\0') {
199 assert(unknown == NULL);
200 unknown = o;
201 assert(unknown->valtype == 0 || unknown->valtype == '-');
202 }
203 }
204 return prog;
205}
206
207static OPT_PAIR formats[] = {
208 {"PEM/DER", OPT_FMT_PEMDER},
209 {"pkcs12", OPT_FMT_PKCS12},
210 {"smime", OPT_FMT_SMIME},
211 {"engine", OPT_FMT_ENGINE},
212 {"msblob", OPT_FMT_MSBLOB},
213 {"netscape", OPT_FMT_NETSCAPE},
214 {"nss", OPT_FMT_NSS},
215 {"text", OPT_FMT_TEXT},
216 {"http", OPT_FMT_HTTP},
217 {"pvk", OPT_FMT_PVK},
218 {NULL}
219};
220
221/* Print an error message about a failed format parse. */
222int opt_format_error(const char *s, unsigned long flags)
223{
224 OPT_PAIR *ap;
225
226 if (flags == OPT_FMT_PEMDER)
227 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n",
228 prog, s);
229 else {
230 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n",
231 prog, s);
232 for (ap = formats; ap->name; ap++)
233 if (flags & ap->retval)
234 BIO_printf(bio_err, " %s\n", ap->name);
235 }
236 return 0;
237}
238
239/* Parse a format string, put it into *result; return 0 on failure, else 1. */
240int opt_format(const char *s, unsigned long flags, int *result)
241{
242 switch (*s) {
243 default:
244 return 0;
245 case 'D':
246 case 'd':
247 if ((flags & OPT_FMT_PEMDER) == 0)
248 return opt_format_error(s, flags);
249 *result = FORMAT_ASN1;
250 break;
251 case 'T':
252 case 't':
253 if ((flags & OPT_FMT_TEXT) == 0)
254 return opt_format_error(s, flags);
255 *result = FORMAT_TEXT;
256 break;
257 case 'N':
258 case 'n':
0bc2f365
RS
259 if ((flags & OPT_FMT_NSS) == 0)
260 return opt_format_error(s, flags);
261 if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
262 return opt_format_error(s, flags);
263 *result = FORMAT_NSS;
7e1b7485
RS
264 break;
265 case 'S':
266 case 's':
267 if ((flags & OPT_FMT_SMIME) == 0)
268 return opt_format_error(s, flags);
269 *result = FORMAT_SMIME;
270 break;
271 case 'M':
272 case 'm':
273 if ((flags & OPT_FMT_MSBLOB) == 0)
274 return opt_format_error(s, flags);
275 *result = FORMAT_MSBLOB;
276 break;
277 case 'E':
278 case 'e':
279 if ((flags & OPT_FMT_ENGINE) == 0)
280 return opt_format_error(s, flags);
281 *result = FORMAT_ENGINE;
282 break;
283 case 'H':
284 case 'h':
285 if ((flags & OPT_FMT_HTTP) == 0)
286 return opt_format_error(s, flags);
287 *result = FORMAT_HTTP;
288 break;
289 case '1':
290 if ((flags & OPT_FMT_PKCS12) == 0)
291 return opt_format_error(s, flags);
292 *result = FORMAT_PKCS12;
293 break;
294 case 'P':
295 case 'p':
296 if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
297 if ((flags & OPT_FMT_PEMDER) == 0)
298 return opt_format_error(s, flags);
299 *result = FORMAT_PEM;
300 } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
301 if ((flags & OPT_FMT_PVK) == 0)
302 return opt_format_error(s, flags);
303 *result = FORMAT_PVK;
304 } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
305 || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
306 if ((flags & OPT_FMT_PKCS12) == 0)
307 return opt_format_error(s, flags);
308 *result = FORMAT_PKCS12;
309 } else
310 return 0;
311 break;
312 }
313 return 1;
314}
315
316/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */
317int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
318{
319 *cipherp = EVP_get_cipherbyname(name);
320 if (*cipherp)
321 return 1;
322 BIO_printf(bio_err, "%s: Unknown cipher %s\n", prog, name);
323 return 0;
324}
325
326/*
327 * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
328 */
329int opt_md(const char *name, const EVP_MD **mdp)
330{
331 *mdp = EVP_get_digestbyname(name);
332 if (*mdp)
333 return 1;
334 BIO_printf(bio_err, "%s: Unknown digest %s\n", prog, name);
335 return 0;
336}
337
338/* Look through a list of name/value pairs. */
339int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
340{
341 const OPT_PAIR *pp;
342
343 for (pp = pairs; pp->name; pp++)
344 if (strcmp(pp->name, name) == 0) {
345 *result = pp->retval;
346 return 1;
347 }
348 BIO_printf(bio_err, "%s: Value must be one of:\n", prog);
349 for (pp = pairs; pp->name; pp++)
350 BIO_printf(bio_err, "\t%s\n", pp->name);
351 return 0;
352}
353
7e1b7485
RS
354/* Parse an int, put it into *result; return 0 on failure, else 1. */
355int opt_int(const char *value, int *result)
356{
bd4850df
RS
357 long l;
358
359 if (!opt_long(value, &l))
360 return 0;
361 *result = (int)l;
362 if (*result != l) {
363 BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n",
7e1b7485
RS
364 prog, value);
365 return 0;
366 }
367 return 1;
368}
369
370/* Parse a long, put it into *result; return 0 on failure, else 1. */
371int opt_long(const char *value, long *result)
372{
bd4850df
RS
373 int oerrno = errno;
374 long l;
375 char *endp;
376
377 l = strtol(value, &endp, 0);
378 if (*endp
379 || endp == value
380 || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
381 || (l == 0 && errno != 0)) {
382 BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
383 prog, value);
384 errno = oerrno;
7e1b7485
RS
385 return 0;
386 }
bd4850df
RS
387 *result = l;
388 errno = oerrno;
7e1b7485
RS
389 return 1;
390}
391
392/*
393 * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
394 */
395int opt_ulong(const char *value, unsigned long *result)
396{
bd4850df 397 int oerrno = errno;
7e1b7485 398 char *endptr;
bd4850df
RS
399 unsigned long l;
400
401 l = strtoul(value, &endptr, 0);
402 if (*endptr
403 || endptr == value
404 || ((l == ULONG_MAX) && errno == ERANGE)
405 || (l == 0 && errno != 0)) {
406 BIO_printf(bio_err, "%s: Can't parse \"%s\" as an unsigned number\n",
407 prog, value);
408 errno = oerrno;
7e1b7485
RS
409 return 0;
410 }
bd4850df
RS
411 *result = l;
412 errno = oerrno;
7e1b7485
RS
413 return 1;
414}
415
416/*
417 * We pass opt as an int but cast it to "enum range" so that all the
418 * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
419 * in gcc do the right thing.
420 */
421enum range { OPT_V_ENUM };
422
423int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
424{
bd4850df 425 long l;
7e1b7485
RS
426 int i;
427 ASN1_OBJECT *otmp;
428 X509_PURPOSE *xptmp;
429 const X509_VERIFY_PARAM *vtmp;
430
431 assert(vpm != NULL);
432 assert(opt > OPT_V__FIRST);
433 assert(opt < OPT_V__LAST);
434
435 switch ((enum range)opt) {
436 case OPT_V__FIRST:
437 case OPT_V__LAST:
438 return 0;
439 case OPT_V_POLICY:
440 otmp = OBJ_txt2obj(opt_arg(), 0);
441 if (otmp == NULL) {
442 BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg());
443 return 0;
444 }
445 X509_VERIFY_PARAM_add0_policy(vpm, otmp);
446 break;
447 case OPT_V_PURPOSE:
448 i = X509_PURPOSE_get_by_sname(opt_arg());
449 if (i < 0) {
450 BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
451 return 0;
452 }
453 xptmp = X509_PURPOSE_get0(i);
454 i = X509_PURPOSE_get_id(xptmp);
455 X509_VERIFY_PARAM_set_purpose(vpm, i);
456 break;
457 case OPT_V_VERIFY_NAME:
458 vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
459 if (vtmp == NULL) {
460 BIO_printf(bio_err, "%s: Invalid verify name %s\n",
461 prog, opt_arg());
462 return 0;
463 }
464 X509_VERIFY_PARAM_set1(vpm, vtmp);
465 break;
466 case OPT_V_VERIFY_DEPTH:
467 i = atoi(opt_arg());
468 if (i >= 0)
469 X509_VERIFY_PARAM_set_depth(vpm, i);
470 break;
471 case OPT_V_ATTIME:
bd4850df
RS
472 /* If we have C99 we could use intmax_t for all time_t values */
473 opt_long(opt_arg(), &l);
474 if (l)
475 X509_VERIFY_PARAM_set_time(vpm, (time_t)l);
7e1b7485
RS
476 break;
477 case OPT_V_VERIFY_HOSTNAME:
478 if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
479 return 0;
480 break;
481 case OPT_V_VERIFY_EMAIL:
482 if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
483 return 0;
484 break;
485 case OPT_V_VERIFY_IP:
486 if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
487 return 0;
488 break;
489 case OPT_V_IGNORE_CRITICAL:
490 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
491 break;
492 case OPT_V_ISSUER_CHECKS:
493 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CB_ISSUER_CHECK);
494 break;
495 case OPT_V_CRL_CHECK:
496 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
497 break;
498 case OPT_V_CRL_CHECK_ALL:
499 X509_VERIFY_PARAM_set_flags(vpm,
500 X509_V_FLAG_CRL_CHECK |
501 X509_V_FLAG_CRL_CHECK_ALL);
502 break;
503 case OPT_V_POLICY_CHECK:
504 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
505 break;
506 case OPT_V_EXPLICIT_POLICY:
507 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
508 break;
509 case OPT_V_INHIBIT_ANY:
510 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
511 break;
512 case OPT_V_INHIBIT_MAP:
513 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
514 break;
515 case OPT_V_X509_STRICT:
516 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
517 break;
518 case OPT_V_EXTENDED_CRL:
519 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
520 break;
521 case OPT_V_USE_DELTAS:
522 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
523 break;
524 case OPT_V_POLICY_PRINT:
525 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
526 break;
527 case OPT_V_CHECK_SS_SIG:
528 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
529 break;
530 case OPT_V_TRUSTED_FIRST:
531 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
532 break;
533 case OPT_V_SUITEB_128_ONLY:
534 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
535 break;
536 case OPT_V_SUITEB_128:
537 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
538 break;
539 case OPT_V_SUITEB_192:
540 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
541 break;
542 case OPT_V_PARTIAL_CHAIN:
543 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
544 break;
545 case OPT_V_NO_ALT_CHAINS:
546 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
d35ff2c0
DW
547 break;
548 case OPT_V_NO_CHECK_TIME:
549 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
550 break;
7e1b7485
RS
551 }
552 return 1;
553
554}
555
556/*
557 * Parse the next flag (and value if specified), return 0 if done, -1 on
558 * error, otherwise the flag's retval.
559 */
560int opt_next(void)
561{
562 char *p;
7e1b7485 563 const OPTIONS *o;
bd4850df
RS
564 int ival;
565 unsigned long uval;
7e1b7485
RS
566
567 /* Look at current arg; at end of the list? */
568 arg = NULL;
569 p = argv[opt_index];
570 if (p == NULL)
571 return 0;
572
573 /* If word doesn't start with a -, we're done. */
574 if (*p != '-')
575 return 0;
576
577 /* Hit "--" ? We're done. */
578 opt_index++;
579 if (strcmp(p, "--") == 0)
580 return 0;
581
582 /* Allow -nnn and --nnn */
583 if (*++p == '-')
584 p++;
585 flag = p - 1;
586
587 /* If we have --flag=foo, snip it off */
588 if ((arg = strchr(p, '=')) != NULL)
589 *arg++ = '\0';
590 for (o = opts; o->name; ++o) {
591 /* If not this option, move on to the next one. */
592 if (strcmp(p, o->name) != 0)
593 continue;
594
595 /* If it doesn't take a value, make sure none was given. */
596 if (o->valtype == 0 || o->valtype == '-') {
597 if (arg) {
598 BIO_printf(bio_err,
599 "%s: Option -%s does not take a value\n", prog, p);
600 return -1;
601 }
602 return o->retval;
603 }
604
605 /* Want a value; get the next param if =foo not used. */
606 if (arg == NULL) {
607 if (argv[opt_index] == NULL) {
608 BIO_printf(bio_err,
609 "%s: Option -%s needs a value\n", prog, o->name);
610 return -1;
611 }
612 arg = argv[opt_index++];
613 }
614
615 /* Syntax-check value. */
7e1b7485
RS
616 switch (o->valtype) {
617 default:
618 case 's':
619 /* Just a string. */
620 break;
621 case '/':
622 if (app_isdir(arg) >= 0)
623 break;
624 BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg);
625 return -1;
626 case '<':
627 /* Input file. */
628 if (strcmp(arg, "-") == 0 || app_access(arg, R_OK) >= 0)
629 break;
630 BIO_printf(bio_err,
631 "%s: Cannot open input file %s, %s\n",
632 prog, arg, strerror(errno));
633 return -1;
634 case '>':
635 /* Output file. */
636 if (strcmp(arg, "-") == 0 || app_access(arg, W_OK) >= 0 || errno == ENOENT)
637 break;
638 BIO_printf(bio_err,
639 "%s: Cannot open output file %s, %s\n",
640 prog, arg, strerror(errno));
641 return -1;
642 case 'p':
643 case 'n':
bd4850df
RS
644 if (!opt_int(arg, &ival)
645 || (o->valtype == 'p' && ival <= 0)) {
646 BIO_printf(bio_err,
647 "%s: Non-positive number \"%s\" for -%s\n",
648 prog, arg, o->name);
649 return -1;
7e1b7485 650 }
bd4850df 651 break;
7e1b7485 652 case 'u':
bd4850df
RS
653 if (!opt_ulong(arg, &uval)) {
654 BIO_printf(bio_err,
655 "%s: Invalid number \"%s\" for -%s\n",
656 prog, arg, o->name);
657 return -1;
658 }
659 break;
7e1b7485
RS
660 case 'f':
661 case 'F':
662 if (opt_format(arg,
663 o->valtype == 'F' ? OPT_FMT_PEMDER
bd4850df 664 : OPT_FMT_ANY, &ival))
7e1b7485
RS
665 break;
666 BIO_printf(bio_err,
667 "%s: Invalid format \"%s\" for -%s\n",
668 prog, arg, o->name);
669 return -1;
670 }
671
672 /* Return the flag value. */
673 return o->retval;
674 }
675 if (unknown != NULL) {
676 dunno = p;
677 return unknown->retval;
678 }
679 BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p);
680 return -1;
681}
682
683/* Return the most recent flag parameter. */
684char *opt_arg(void)
685{
686 return arg;
687}
688
689/* Return the most recent flag. */
690char *opt_flag(void)
691{
692 return flag;
693}
694
695/* Return the unknown option. */
696char *opt_unknown(void)
697{
698 return dunno;
699}
700
701/* Return the rest of the arguments after parsing flags. */
702char **opt_rest(void)
703{
704 return &argv[opt_index];
705}
706
707/* How many items in remaining args? */
708int opt_num_rest(void)
709{
710 int i = 0;
711 char **pp;
712
713 for (pp = opt_rest(); *pp; pp++, i++)
714 continue;
715 return i;
716}
717
718/* Return a string describing the parameter type. */
719static const char *valtype2param(const OPTIONS *o)
720{
721 switch (o->valtype) {
722 case '-':
723 return "";
724 case 's':
725 return "val";
726 case '/':
727 return "dir";
728 case '<':
729 return "infile";
730 case '>':
731 return "outfile";
732 case 'p':
733 return "pnum";
734 case 'n':
735 return "num";
736 case 'u':
737 return "unum";
738 case 'F':
739 return "der/pem";
740 case 'f':
741 return "format";
742 }
743 return "parm";
744}
745
746void opt_help(const OPTIONS *list)
747{
748 const OPTIONS *o;
749 int i;
750 int standard_prolog;
751 int width = 5;
752 char start[80 + 1];
753 char *p;
754 const char *help;
755
756 /* Starts with its own help message? */
757 standard_prolog = list[0].name != OPT_HELP_STR;
758
759 /* Find the widest help. */
760 for (o = list; o->name; o++) {
761 if (o->name == OPT_MORE_STR)
762 continue;
763 i = 2 + (int)strlen(o->name);
764 if (o->valtype != '-')
765 i += 1 + strlen(valtype2param(o));
766 if (i < MAX_OPT_HELP_WIDTH && i > width)
767 width = i;
768 assert(i < (int)sizeof start);
769 }
770
771 if (standard_prolog)
772 BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n",
773 prog);
774
775 /* Now let's print. */
776 for (o = list; o->name; o++) {
777 help = o->helpstr ? o->helpstr : "(No additional info)";
778 if (o->name == OPT_HELP_STR) {
779 BIO_printf(bio_err, help, prog);
780 continue;
781 }
782
783 /* Pad out prefix */
16f8d4eb 784 memset(start, ' ', sizeof(start) - 1);
7e1b7485
RS
785 start[sizeof start - 1] = '\0';
786
787 if (o->name == OPT_MORE_STR) {
788 /* Continuation of previous line; padd and print. */
789 start[width] = '\0';
790 BIO_printf(bio_err, "%s %s\n", start, help);
791 continue;
792 }
793
794 /* Build up the "-flag [param]" part. */
795 p = start;
796 *p++ = ' ';
797 *p++ = '-';
798 if (o->name[0])
799 p += strlen(strcpy(p, o->name));
800 else
801 *p++ = '*';
802 if (o->valtype != '-') {
803 *p++ = ' ';
804 p += strlen(strcpy(p, valtype2param(o)));
805 }
806 *p = ' ';
807 if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
808 *p = '\0';
809 BIO_printf(bio_err, "%s\n", start);
16f8d4eb 810 memset(start, ' ', sizeof(start));
7e1b7485
RS
811 }
812 start[width] = '\0';
813 BIO_printf(bio_err, "%s %s\n", start, help);
814 }
815}
816
817#ifdef COMPILE_STANDALONE_TEST_DRIVER
818# include <sys/stat.h>
819
820typedef enum OPTION_choice {
821 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
822 OPT_IN, OPT_INFORM, OPT_OUT, OPT_COUNT, OPT_U, OPT_FLAG,
823 OPT_STR, OPT_NOTUSED
824} OPTION_CHOICE;
825
826static OPTIONS options[] = {
827 {OPT_HELP_STR, 1, '-', "Usage: %s flags\n"},
828 {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
829 {"help", OPT_HELP, '-', "Display this summary"},
830 {"in", OPT_IN, '<', "input file"},
831 {OPT_MORE_STR, 1, '-', "more detail about input"},
832 {"inform", OPT_INFORM, 'f', "input file format; defaults to pem"},
833 {"out", OPT_OUT, '>', "output file"},
834 {"count", OPT_COUNT, 'p', "a counter greater than zero"},
835 {"u", OPT_U, 'u', "an unsigned number"},
836 {"flag", OPT_FLAG, 0, "just some flag"},
837 {"str", OPT_STR, 's', "the magic word"},
838 {"areallyverylongoption", OPT_HELP, '-', "long way for help"},
839 {NULL}
840};
841
842BIO *bio_err;
843
844int app_isdir(const char *name)
845{
846 struct stat sb;
847
848 return name != NULL && stat(name, &sb) >= 0 && S_ISDIR(sb.st_mode);
849}
850
851int main(int ac, char **av)
852{
853 OPTION_CHOICE o;
854 char **rest;
855 char *prog;
856
857 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
858
859 prog = opt_init(ac, av, options);
860 while ((o = opt_next()) != OPT_EOF) {
861 switch (c) {
862 case OPT_NOTUSED:
863 case OPT_EOF:
864 case OPT_ERR:
865 printf("%s: Usage error; try -help.\n", prog);
866 return 1;
867 case OPT_HELP:
868 opt_help(options);
869 return 0;
870 case OPT_IN:
871 printf("in %s\n", opt_arg());
872 break;
873 case OPT_INFORM:
874 printf("inform %s\n", opt_arg());
875 break;
876 case OPT_OUT:
877 printf("out %s\n", opt_arg());
878 break;
879 case OPT_COUNT:
880 printf("count %s\n", opt_arg());
881 break;
882 case OPT_U:
883 printf("u %s\n", opt_arg());
884 break;
885 case OPT_FLAG:
886 printf("flag\n");
887 break;
888 case OPT_STR:
889 printf("str %s\n", opt_arg());
890 break;
891 }
892 }
893 argc = opt_num_rest();
894 argv = opt_rest();
895
896 printf("args = %d\n", argc);
897 if (argc)
898 while (*argv)
899 printf(" %s\n", *argv++);
900 return 0;
901}
902#endif