summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2014-08-27 14:59:44 +0000
committerjsing <>2014-08-27 14:59:44 +0000
commit1fbc8b7e3211e362b5507749d1c5b692dcb8c64f (patch)
treed84799ea674d39450c109ebc4c3cb39140e5201e /src
parent10e31157bd2d409218ed09f4b52af2de773a8a0f (diff)
downloadopenbsd-1fbc8b7e3211e362b5507749d1c5b692dcb8c64f.tar.gz
openbsd-1fbc8b7e3211e362b5507749d1c5b692dcb8c64f.tar.bz2
openbsd-1fbc8b7e3211e362b5507749d1c5b692dcb8c64f.zip
Implement table-driven option parsing that allows an application to
specify what its valid options are and where it wants them to be stored. This also allows for usage to be generated, almost for free, ensuring that the options and usage are automatically kept in sync. This will allow for a single option parsing implementation, rather than the current one-hand-rolled-option-parsing-and-random-usage-implementation per application. As a starting point, port the openssl(1) rand application to the new option parsing and usage (along with associated code clean up). With input from doug@. ok bcook@ doug@
Diffstat (limited to 'src')
-rw-r--r--src/usr.bin/openssl/apps.c97
-rw-r--r--src/usr.bin/openssl/apps.h22
-rw-r--r--src/usr.bin/openssl/rand.c149
3 files changed, 192 insertions, 76 deletions
diff --git a/src/usr.bin/openssl/apps.c b/src/usr.bin/openssl/apps.c
index ac1c5107f1..e5eda3f53b 100644
--- a/src/usr.bin/openssl/apps.c
+++ b/src/usr.bin/openssl/apps.c
@@ -1,4 +1,19 @@
1/* $OpenBSD: apps.c,v 1.1 2014/08/26 17:47:24 jsing Exp $ */ 1/* $OpenBSD: apps.c,v 1.2 2014/08/27 14:59:44 jsing Exp $ */
2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 17/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 18 * All rights reserved.
4 * 19 *
@@ -2218,3 +2233,83 @@ app_isdir(const char *name)
2218 return S_ISDIR(st.st_mode); 2233 return S_ISDIR(st.st_mode);
2219 return -1; 2234 return -1;
2220} 2235}
2236
2237void
2238options_usage(struct option *opts)
2239{
2240 const char *argname;
2241 char buf[32];
2242 int i;
2243
2244 for (i = 0; opts[i].name != NULL; i++) {
2245 if (opts[i].desc == NULL)
2246 continue;
2247 argname = (opts[i].argname != NULL) ? opts[i].argname : "";
2248 snprintf(buf, sizeof(buf), "-%s %s", opts[i].name, argname);
2249 fprintf(stderr, " %-*s %s\n", 14, buf, opts[i].desc);
2250 }
2251}
2252
2253int
2254options_parse(int argc, char **argv, struct option *opts, char **unnamed)
2255{
2256 struct option *opt;
2257 char *arg, *p;
2258 int i, j;
2259
2260 for (i = 1; i < argc; i++) {
2261 p = arg = argv[i];
2262
2263 if (*p++ != '-') {
2264 if (unnamed == NULL)
2265 goto unknown;
2266 *unnamed = arg;
2267 continue;
2268 }
2269 if (*p == '\0')
2270 goto unknown;
2271
2272 for (j = 0; opts[j].name != NULL; j++) {
2273 opt = &opts[j];
2274 if (strcmp(p, opt->name) != 0)
2275 continue;
2276
2277 switch (opt->type) {
2278 case OPTION_ARG:
2279 if (++i >= argc) {
2280 fprintf(stderr,
2281 "missing %s argument for -%s\n",
2282 opt->argname, opt->name);
2283 return (1);
2284 }
2285 *opt->opt.arg = argv[i];
2286 break;
2287
2288 case OPTION_FLAG:
2289 *opt->opt.flag = 1;
2290 break;
2291
2292 case OPTION_VALUE:
2293 *opt->opt.value = opt->value;
2294 break;
2295
2296 default:
2297 fprintf(stderr,
2298 "option %s - unknown type %i\n",
2299 opt->name, opt->type);
2300 return (1);
2301 }
2302
2303 break;
2304 }
2305
2306 if (opts[j].name == NULL)
2307 goto unknown;
2308 }
2309
2310 return (0);
2311
2312unknown:
2313 fprintf(stderr, "unknown option '%s'\n", arg);
2314 return (1);
2315}
diff --git a/src/usr.bin/openssl/apps.h b/src/usr.bin/openssl/apps.h
index 38c5f4be8c..64e581b969 100644
--- a/src/usr.bin/openssl/apps.h
+++ b/src/usr.bin/openssl/apps.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: apps.h,v 1.1 2014/08/26 17:47:24 jsing Exp $ */ 1/* $OpenBSD: apps.h,v 1.2 2014/08/27 14:59:44 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -282,4 +282,24 @@ double app_tminterval (int stop, int usertime);
282 282
283#define OPENSSL_NO_SSL_INTERN 283#define OPENSSL_NO_SSL_INTERN
284 284
285struct option {
286 const char *name;
287 const char *argname;
288 const char *desc;
289 enum {
290 OPTION_ARG,
291 OPTION_FLAG,
292 OPTION_VALUE,
293 } type;
294 union {
295 char **arg;
296 int *flag;
297 int *value;
298 } opt;
299 const int value;
300};
301
302void options_usage(struct option *opts);
303int options_parse(int argc, char **argv, struct option *opts, char **unnamed);
304
285#endif 305#endif
diff --git a/src/usr.bin/openssl/rand.c b/src/usr.bin/openssl/rand.c
index 0800157a35..61c7013340 100644
--- a/src/usr.bin/openssl/rand.c
+++ b/src/usr.bin/openssl/rand.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: rand.c,v 1.1 2014/08/26 17:47:25 jsing Exp $ */ 1/* $OpenBSD: rand.c,v 1.2 2014/08/27 14:59:44 jsing Exp $ */
2/* ==================================================================== 2/* ====================================================================
3 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 3 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
4 * 4 *
@@ -63,123 +63,124 @@
63#include <openssl/err.h> 63#include <openssl/err.h>
64#include <openssl/rand.h> 64#include <openssl/rand.h>
65 65
66/* -out file - write to file 66struct {
67 * -base64 - base64 encode output 67 int base64;
68 * -hex - hex encode output 68 char *engine;
69 * num - write 'num' bytes 69 int hex;
70 */ 70 char *outfile;
71} rand_config;
72
73struct option rand_options[] = {
74 {
75 .name = "base64",
76 .desc = "Perform base64 encoding on output",
77 .type = OPTION_FLAG,
78 .opt.flag = &rand_config.base64,
79 },
80#ifndef OPENSSL_NO_ENGINE
81 {
82 .name = "engine",
83 .argname = "id",
84 .desc = "Use the engine specified by the given identifier",
85 .type = OPTION_ARG,
86 .opt.arg = &rand_config.engine,
87 },
88#endif
89 {
90 .name = "hex",
91 .desc = "Hexadecimal output",
92 .type = OPTION_FLAG,
93 .opt.flag = &rand_config.hex,
94 },
95 {
96 .name = "out",
97 .argname = "file",
98 .desc = "Write to the given file instead of standard output",
99 .type = OPTION_ARG,
100 .opt.arg = &rand_config.outfile,
101 },
102 {},
103};
104
105static void
106rand_usage()
107{
108 fprintf(stderr,
109 "usage: rand [-base64 | -hex] [-engine id] [-out file] num\n");
110 options_usage(rand_options);
111}
71 112
72int rand_main(int, char **); 113int rand_main(int, char **);
73 114
74int 115int
75rand_main(int argc, char **argv) 116rand_main(int argc, char **argv)
76{ 117{
77 int i, r, ret = 1; 118 char *num_bytes = NULL;
78 int badopt; 119 int ret = 1;
79 char *outfile = NULL; 120 int badopt = 0;
80 int base64 = 0;
81 int hex = 0;
82 BIO *out = NULL;
83 int num = -1; 121 int num = -1;
84#ifndef OPENSSL_NO_ENGINE 122 int i, r;
85 char *engine = NULL; 123 BIO *out = NULL;
86#endif
87 124
88 badopt = 0; 125 if (options_parse(argc, argv, rand_options, &num_bytes) != 0) {
89 i = 0; 126 rand_usage();
90 while (!badopt && argv[++i] != NULL) { 127 return (1);
91 if (strcmp(argv[i], "-out") == 0) {
92 if ((argv[i + 1] != NULL) && (outfile == NULL))
93 outfile = argv[++i];
94 else
95 badopt = 1;
96 }
97#ifndef OPENSSL_NO_ENGINE
98 else if (strcmp(argv[i], "-engine") == 0) {
99 if ((argv[i + 1] != NULL) && (engine == NULL))
100 engine = argv[++i];
101 else
102 badopt = 1;
103 }
104#endif
105 else if (strcmp(argv[i], "-base64") == 0) {
106 if (!base64)
107 base64 = 1;
108 else
109 badopt = 1;
110 } else if (strcmp(argv[i], "-hex") == 0) {
111 if (!hex)
112 hex = 1;
113 else
114 badopt = 1;
115 } else if (isdigit((unsigned char) argv[i][0])) {
116 if (num < 0) {
117 r = sscanf(argv[i], "%d", &num);
118 if (r == 0 || num < 0)
119 badopt = 1;
120 } else
121 badopt = 1;
122 } else
123 badopt = 1;
124 } 128 }
125 129
126 if (hex && base64) 130 if (num_bytes != NULL) {
131 r = sscanf(num_bytes, "%d", &num);
132 if (r == 0 || num < 0)
133 badopt = 1;
134 } else
127 badopt = 1; 135 badopt = 1;
128 136
129 if (num < 0) 137 if (rand_config.hex && rand_config.base64)
130 badopt = 1; 138 badopt = 1;
131 139
132 if (badopt) { 140 if (badopt) {
133 BIO_printf(bio_err, "Usage: rand [options] num\n"); 141 rand_usage();
134 BIO_printf(bio_err, "where options are\n");
135 BIO_printf(bio_err, "-out file - write to file\n");
136#ifndef OPENSSL_NO_ENGINE
137 BIO_printf(bio_err, "-engine e - use engine e, possibly a hardware device.\n");
138#endif
139 BIO_printf(bio_err, "-base64 - base64 encode output\n");
140 BIO_printf(bio_err, "-hex - hex encode output\n");
141 goto err; 142 goto err;
142 } 143 }
144
143#ifndef OPENSSL_NO_ENGINE 145#ifndef OPENSSL_NO_ENGINE
144 setup_engine(bio_err, engine, 0); 146 setup_engine(bio_err, rand_config.engine, 0);
145#endif 147#endif
146 148
147 out = BIO_new(BIO_s_file()); 149 out = BIO_new(BIO_s_file());
148 if (out == NULL) 150 if (out == NULL)
149 goto err; 151 goto err;
150 if (outfile != NULL) 152 if (rand_config.outfile != NULL)
151 r = BIO_write_filename(out, outfile); 153 r = BIO_write_filename(out, rand_config.outfile);
152 else { 154 else
153 r = BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); 155 r = BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
154 }
155 if (r <= 0) 156 if (r <= 0)
156 goto err; 157 goto err;
157 158 if (rand_config.base64) {
158 if (base64) {
159 BIO *b64 = BIO_new(BIO_f_base64()); 159 BIO *b64 = BIO_new(BIO_f_base64());
160 if (b64 == NULL) 160 if (b64 == NULL)
161 goto err; 161 goto err;
162 out = BIO_push(b64, out); 162 out = BIO_push(b64, out);
163 } 163 }
164
164 while (num > 0) { 165 while (num > 0) {
165 unsigned char buf[4096]; 166 unsigned char buf[4096];
166 int chunk; 167 int chunk;
167 168
168 chunk = num; 169 chunk = num;
169 if (chunk > (int) sizeof(buf)) 170 if (chunk > (int) sizeof(buf))
170 chunk = sizeof buf; 171 chunk = sizeof(buf);
171 r = RAND_bytes(buf, chunk); 172 r = RAND_bytes(buf, chunk);
172 if (r <= 0) 173 if (r <= 0)
173 goto err; 174 goto err;
174 if (!hex) 175 if (rand_config.hex) {
175 BIO_write(out, buf, chunk);
176 else {
177 for (i = 0; i < chunk; i++) 176 for (i = 0; i < chunk; i++)
178 BIO_printf(out, "%02x", buf[i]); 177 BIO_printf(out, "%02x", buf[i]);
179 } 178 } else
179 BIO_write(out, buf, chunk);
180 num -= chunk; 180 num -= chunk;
181 } 181 }
182 if (hex) 182
183 if (rand_config.hex)
183 BIO_puts(out, "\n"); 184 BIO_puts(out, "\n");
184 (void) BIO_flush(out); 185 (void) BIO_flush(out);
185 186