diff --git a/Makefile b/Makefile index f70a8e4..86cc255 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ P = otpcli V = 0.0 -HDR = err.h otp.h -OBJ = cli.o err.o otp.o +HDR = err.h mystrtonum.h otp.h +OBJ = cli.o err.o mystrtonum.o otp.o SRC = ${OBJ:.o=.c} DIST_FILES = COPYING Makefile ${HDR} ${SRC} diff --git a/cli.c b/cli.c index 87e0215..bc264cd 100644 --- a/cli.c +++ b/cli.c @@ -22,6 +22,7 @@ #include #include "err.h" +#include "mystrtonum.h" #include "otp.h" extern const char *__progname; @@ -36,8 +37,7 @@ usage(void) int main(int argc, char *argv[]) { - char *end; - uintmax_t n; + const char *errstr; uint64_t counter; int32_t r; int ch, do_hotp; @@ -47,15 +47,9 @@ main(int argc, char *argv[]) while ((ch = getopt(argc, argv, "H:")) != -1) { switch (ch) { case 'H': - errno = 0; - n = strtoumax(optarg, &end, 0); - if (*optarg == '\0' || *end != '\0') - errx(1, "-H: not a number"); - if (errno != 0) - err(1, "-H"); - else if (n > UINT64_MAX) - errx(1, "-H: out of range"); - counter = n; + counter = mystrtonum(optarg, 0, LLONG_MAX, &errstr); + if (errstr != NULL) + errx(1, "counter is %s: %s", errstr, optarg); do_hotp = 1; break; default: diff --git a/mystrtonum.c b/mystrtonum.c new file mode 100644 index 0000000..3ad8e34 --- /dev/null +++ b/mystrtonum.c @@ -0,0 +1,67 @@ +/* This is OpenBSD's strtonum(3), renamed to mystrtonum */ + +/* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +mystrtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} diff --git a/mystrtonum.h b/mystrtonum.h new file mode 100644 index 0000000..742100e --- /dev/null +++ b/mystrtonum.h @@ -0,0 +1,16 @@ +/* + * libutil - C utility functions + * + * Written in 2020 by Lucas + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +long long mystrtonum(const char *, long long, long long, const char **);