Viewing file: bio_prefix_text.c (7.39 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */
#include <string.h> #include <stdarg.h> #include <openssl/bio.h> #include <openssl/safestack.h> #include "opt.h"
static BIO *bio_in = NULL; static BIO *bio_out = NULL; static BIO *bio_err = NULL;
/*- * This program sets up a chain of BIO_f_filter() on top of bio_out, how * many is governed by the user through -n. It allows the user to set the * indentation for each individual filter using -i and -p. Then it reads * text from bio_in and prints it out through the BIO chain. * * The filter index is counted from the source/sink, i.e. index 0 is closest * to it. * * Example: * * $ echo foo | ./bio_prefix_text -n 2 -i 1:32 -p 1:FOO -i 0:3 * FOO foo * ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * | | * | +------ 32 spaces from filter 1 * +-------------------------- 3 spaces from filter 0 */
static size_t amount = 0; static BIO **chain = NULL;
typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_AMOUNT, OPT_INDENT, OPT_PREFIX } OPTION_CHOICE;
static const OPTIONS options[] = { { "n", OPT_AMOUNT, 'p', "Amount of BIO_f_prefix() filters" }, /* * idx is the index to the BIO_f_filter chain(), where 0 is closest * to the source/sink BIO. If idx isn't given, 0 is assumed */ { "i", OPT_INDENT, 's', "Indentation in form '[idx:]indent'" }, { "p", OPT_PREFIX, 's', "Prefix in form '[idx:]prefix'" }, { NULL } };
int opt_printf_stderr(const char *fmt, ...) { va_list ap; int ret;
va_start(ap, fmt); ret = BIO_vprintf(bio_err, fmt, ap); va_end(ap); return ret; }
static int run_pipe(void) { char buf[4096];
while (!BIO_eof(bio_in)) { size_t bytes_in; size_t bytes_out;
if (!BIO_read_ex(bio_in, buf, sizeof(buf), &bytes_in)) return 0; bytes_out = 0; while (bytes_out < bytes_in) { size_t bytes;
if (!BIO_write_ex(chain[amount - 1], buf, bytes_in, &bytes)) return 0; bytes_out += bytes; } } return 1; }
static int setup_bio_chain(const char *progname) { BIO *next = NULL; size_t n = amount;
chain = OPENSSL_zalloc(sizeof(*chain) * n);
if (chain != NULL) { size_t i;
next = bio_out; BIO_up_ref(next); /* Protection against freeing */
for (i = 0; n > 0; i++, n--) { BIO *curr = BIO_new(BIO_f_prefix());
if (curr == NULL) goto err; chain[i] = BIO_push(curr, next); if (chain[i] == NULL) goto err; next = chain[i]; } } return chain != NULL; err: /* Free the chain we built up */ BIO_free_all(next); OPENSSL_free(chain); return 0; }
static void cleanup(void) { if (chain != NULL) { BIO_free_all(chain[amount - 1]); OPENSSL_free(chain); }
BIO_free_all(bio_in); BIO_free_all(bio_out); BIO_free_all(bio_err); }
static int setup(void) { OPTION_CHOICE o; char *arg; char *colon; char *endptr; size_t idx, indent; const char *progname = opt_getprog();
bio_in = BIO_new_fp(stdin, BIO_NOCLOSE | BIO_FP_TEXT); bio_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT); bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); #ifdef __VMS bio_out = BIO_push(BIO_new(BIO_f_linebuffer()), bio_out); bio_err = BIO_push(BIO_new(BIO_f_linebuffer()), bio_err); #endif
OPENSSL_assert(bio_in != NULL); OPENSSL_assert(bio_out != NULL); OPENSSL_assert(bio_err != NULL);
while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_AMOUNT: arg = opt_arg(); amount = strtoul(arg, &endptr, 10); if (endptr[0] != '\0') { BIO_printf(bio_err, "%s: -n argument isn't a decimal number: %s", progname, arg); return 0; } if (amount < 1) { BIO_printf(bio_err, "%s: must set up at least one filter", progname); return 0; } if (!setup_bio_chain(progname)) { BIO_printf(bio_err, "%s: failed setting up filter chain", progname); return 0; } break; case OPT_INDENT: if (chain == NULL) { BIO_printf(bio_err, "%s: -i given before -n", progname); return 0; } arg = opt_arg(); colon = strchr(arg, ':'); idx = 0; if (colon != NULL) { idx = strtoul(arg, &endptr, 10); if (endptr[0] != ':') { BIO_printf(bio_err, "%s: -i index isn't a decimal number: %s", progname, arg); return 0; } colon++; } else { colon = arg; } indent = strtoul(colon, &endptr, 10); if (endptr[0] != '\0') { BIO_printf(bio_err, "%s: -i value isn't a decimal number: %s", progname, arg); return 0; } if (idx >= amount) { BIO_printf(bio_err, "%s: index (%zu) not within range 0..%zu", progname, idx, amount - 1); return 0; } if (BIO_set_indent(chain[idx], (long)indent) <= 0) { BIO_printf(bio_err, "%s: failed setting indentation: %s", progname, arg); return 0; } break; case OPT_PREFIX: if (chain == NULL) { BIO_printf(bio_err, "%s: -p given before -n", progname); return 0; } arg = opt_arg(); colon = strchr(arg, ':'); idx = 0; if (colon != NULL) { idx = strtoul(arg, &endptr, 10); if (endptr[0] != ':') { BIO_printf(bio_err, "%s: -p index isn't a decimal number: %s", progname, arg); return 0; } colon++; } else { colon = arg; } if (idx >= amount) { BIO_printf(bio_err, "%s: index (%zu) not within range 0..%zu", progname, idx, amount - 1); return 0; } if (BIO_set_prefix(chain[idx], colon) <= 0) { BIO_printf(bio_err, "%s: failed setting prefix: %s", progname, arg); return 0; } break; default: case OPT_ERR: return 0; } } return 1; }
int main(int argc, char **argv) { int rv = EXIT_SUCCESS;
opt_init(argc, argv, options); rv = (setup() && run_pipe()) ? EXIT_SUCCESS : EXIT_FAILURE; cleanup(); return rv; }
|