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