From b6ce735c0405721cb5d833de27a9e848661ef34c Mon Sep 17 00:00:00 2001 From: lukem Date: Sun, 25 Nov 2001 10:50:06 +0000 Subject: [PATCH] - Use u_longlong_t instead of u_quad_t, u_long, or int for various buffer sizes - Add strsuftoull(), which parses a number into a u_longlong_t, with multiplication support, and support for 'g' (GB) and 't' (TB) suffices. If an error occurs, print to stderr and exit. Based on get_blk() from args.c and strsufto*() (in other programs) - Add strsuftoullx(), which acts as per strsuftoull() but returns the error in the supplied buffer instead (if the returned buffer != "", an error occurred) - Replace get_bsz() use with strsuftoull() - Remove (now) unnecessary argument validation - Remove unused {f,p,s,t}_stats fields in struct IO --- bin/dd/Makefile | 4 +- bin/dd/args.c | 111 +++------------------ bin/dd/conv.c | 12 +-- bin/dd/dd.1 | 42 +++++--- bin/dd/dd.c | 29 +++--- bin/dd/dd.h | 41 ++++---- bin/dd/extern.h | 28 +++--- bin/dd/misc.c | 23 +++-- bin/dd/strsuftoull.c | 226 +++++++++++++++++++++++++++++++++++++++++++ bin/dd/strsuftoull.h | 7 ++ 10 files changed, 346 insertions(+), 177 deletions(-) create mode 100644 bin/dd/strsuftoull.c create mode 100644 bin/dd/strsuftoull.h diff --git a/bin/dd/Makefile b/bin/dd/Makefile index 914407e376a8..cb69a586c3c0 100644 --- a/bin/dd/Makefile +++ b/bin/dd/Makefile @@ -1,8 +1,8 @@ -# $NetBSD: Makefile,v 1.7 2001/11/25 06:53:48 lukem Exp $ +# $NetBSD: Makefile,v 1.8 2001/11/25 10:50:06 lukem Exp $ # @(#)Makefile 8.1 (Berkeley) 5/31/93 PROG= dd -SRCS= args.c conv.c conv_tab.c dd.c misc.c position.c +SRCS= args.c conv.c conv_tab.c dd.c misc.c position.c strsuftoull.c WARNS=2 diff --git a/bin/dd/args.c b/bin/dd/args.c index 3863bce1a8d3..35bce911008f 100644 --- a/bin/dd/args.c +++ b/bin/dd/args.c @@ -1,4 +1,4 @@ -/* $NetBSD: args.c,v 1.18 2001/11/25 06:57:55 lukem Exp $ */ +/* $NetBSD: args.c,v 1.19 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: args.c,v 1.18 2001/11/25 06:57:55 lukem Exp $"); +__RCSID("$NetBSD: args.c,v 1.19 2001/11/25 10:50:06 lukem Exp $"); #endif #endif /* not lint */ @@ -58,6 +58,7 @@ __RCSID("$NetBSD: args.c,v 1.18 2001/11/25 06:57:55 lukem Exp $"); #include "dd.h" #include "extern.h" +#include "strsuftoull.h" static int c_arg(const void *, const void *); #ifndef NO_CONV @@ -75,7 +76,6 @@ static void f_of(char *); static void f_seek(char *); static void f_skip(char *); static void f_progress(char *); -static u_long get_bsz(const char *); static const struct arg { const char *name; @@ -98,8 +98,6 @@ static const struct arg { { "skip", f_skip, C_SKIP, C_SKIP }, }; -static char *oper; - /* * args -- parse JCL syntax of dd. */ @@ -107,7 +105,7 @@ void jcl(char **argv) { struct arg *ap, tmp; - char *arg; + char *oper, *arg; in.dbsz = out.dbsz = 512; @@ -153,8 +151,6 @@ jcl(char **argv) if (ddflags & (C_BLOCK|C_UNBLOCK)) { if (!(ddflags & C_CBS)) errx(1, "record operations require cbs"); - if (cbsz == 0) - errx(1, "cbs cannot be zero"); cfunc = ddflags & C_BLOCK ? block : unblock; } else if (ddflags & C_CBS) { if (ddflags & (C_ASCII|C_EBCDIC)) { @@ -168,20 +164,9 @@ jcl(char **argv) } else errx(1, "cbs meaningless if not doing record operations"); - if (cbsz == 0) - errx(1, "cbs cannot be zero"); } else cfunc = def; - if (in.dbsz == 0 || out.dbsz == 0) - errx(1, "buffer sizes cannot be zero"); - - /* - * Check to make sure that the buffers are not too large. - */ - if (in.dbsz > INT_MAX || out.dbsz > INT_MAX) - errx(1, "buffer sizes cannot be greater than %d", INT_MAX); - /* Read, write and seek calls take off_t as arguments. * * The following check is not done because an off_t is a quad @@ -204,21 +189,21 @@ static void f_bs(char *arg) { - in.dbsz = out.dbsz = (int)get_bsz(arg); + in.dbsz = out.dbsz = strsuftoull("block size", arg, 1, UINT_MAX); } static void f_cbs(char *arg) { - cbsz = (int)get_bsz(arg); + cbsz = strsuftoull("conversion record size", arg, 1, UINT_MAX); } static void f_count(char *arg) { - cpy_cnt = (u_int)get_bsz(arg); + cpy_cnt = strsuftoull("block count", arg, 0, ULLONG_MAX); if (!cpy_cnt) terminate(0); } @@ -227,7 +212,9 @@ static void f_files(char *arg) { - files_cnt = (int)get_bsz(arg); + files_cnt = (u_int)strsuftoull("file count", arg, 0, UINT_MAX); + if (!files_cnt) + terminate(0); } static void @@ -235,7 +222,7 @@ f_ibs(char *arg) { if (!(ddflags & C_BS)) - in.dbsz = (int)get_bsz(arg); + in.dbsz = strsuftoull("input block size", arg, 1, UINT_MAX); } static void @@ -250,7 +237,7 @@ f_obs(char *arg) { if (!(ddflags & C_BS)) - out.dbsz = (int)get_bsz(arg); + out.dbsz = strsuftoull("output block size", arg, 1, UINT_MAX); } static void @@ -264,14 +251,14 @@ static void f_seek(char *arg) { - out.offset = (u_int)get_bsz(arg); + out.offset = strsuftoull("seek blocks", arg, 0, ULLONG_MAX); } static void f_skip(char *arg) { - in.offset = (u_int)get_bsz(arg); + in.offset = strsuftoull("skip blocks", arg, 0, ULLONG_MAX); } static void @@ -342,73 +329,3 @@ c_conv(const void *a, const void *b) } #endif /* NO_CONV */ - -/* - * Convert an expression of the following forms to an unsigned long. - * 1) A positive decimal number. - * 2) A positive decimal number followed by a b (mult by 512). - * 3) A positive decimal number followed by a k (mult by 1024). - * 4) A positive decimal number followed by a m (mult by 1048576). - * 5) A positive decimal number followed by a w (mult by sizeof int) - * 6) Two or more positive decimal numbers (with/without k,b or w). - * separated by x (also * for backwards compatibility), specifying - * the product of the indicated values. - */ -static u_long -get_bsz(const char *val) -{ - u_long num, t; - char *expr; - - num = strtoul(val, &expr, 0); - if (num == ULONG_MAX) /* Overflow. */ - err(1, "%s", oper); - if (expr == val) /* No digits. */ - errx(1, "%s: illegal numeric value", oper); - - switch (*expr) { - case 'b': - t = num; - num *= 512; - if (t > num) - goto erange; - ++expr; - break; - case 'k': - t = num; - num *= 1024; - if (t > num) - goto erange; - ++expr; - break; - case 'm': - t = num; - num *= 1048576; - if (t > num) - goto erange; - ++expr; - break; - case 'w': - t = num; - num *= sizeof(int); - if (t > num) - goto erange; - ++expr; - break; - } - - switch (*expr) { - case '\0': - break; - case '*': /* Backward compatible. */ - case 'x': - t = num; - num *= get_bsz(expr + 1); - if (t > num) -erange: errx(1, "%s: %s", oper, strerror(ERANGE)); - break; - default: - errx(1, "%s: illegal numeric value", oper); - } - return (num); -} diff --git a/bin/dd/conv.c b/bin/dd/conv.c index cdeac04650fb..81d85e0c1dcc 100644 --- a/bin/dd/conv.c +++ b/bin/dd/conv.c @@ -1,4 +1,4 @@ -/* $NetBSD: conv.c,v 1.12 2001/11/25 06:53:48 lukem Exp $ */ +/* $NetBSD: conv.c,v 1.13 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: conv.c,v 1.12 2001/11/25 06:53:48 lukem Exp $"); +__RCSID("$NetBSD: conv.c,v 1.13 2001/11/25 10:50:06 lukem Exp $"); #endif #endif /* not lint */ @@ -64,7 +64,7 @@ __RCSID("$NetBSD: conv.c,v 1.12 2001/11/25 06:53:48 lukem Exp $"); void def(void) { - int cnt; + u_longlong_t cnt; u_char *inp; const u_char *t; @@ -121,7 +121,7 @@ block(void) { static int intrunc; int ch = 0; /* pacify gcc */ - int cnt, maxlen; + u_longlong_t cnt, maxlen; u_char *inp, *outp; const u_char *t; @@ -232,7 +232,7 @@ block_close(void) void unblock(void) { - int cnt; + u_longlong_t cnt; u_char *inp; const u_char *t; @@ -266,7 +266,7 @@ unblock(void) void unblock_close(void) { - int cnt; + u_longlong_t cnt; u_char *t; if (in.dbcnt) { diff --git a/bin/dd/dd.1 b/bin/dd/dd.1 index f79707975daf..a1bdf36e89b6 100644 --- a/bin/dd/dd.1 +++ b/bin/dd/dd.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: dd.1,v 1.10 2000/09/04 07:30:08 kleink Exp $ +.\" $NetBSD: dd.1,v 1.11 2001/11/25 10:50:06 lukem Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -36,7 +36,7 @@ .\" .\" @(#)dd.1 8.2 (Berkeley) 1/13/94 .\" -.Dd July 28, 1999 +.Dd November 25, 2001 .Dt DD 1 .Os .Sh NAME @@ -140,8 +140,11 @@ distinguishing between a partial or complete block being read. .It Cm progress= Ns Ar n Switch on display of progress if .Va n -is set to ``1'', i.e. a ``.'' is printed for each -block written to the output file. +is set to +.Dq 1 , +i.e. a +.Dq \&. +is printed for each block written to the output file. .It Xo .Cm conv= .Ns Cm value Ns Op \&, Cm value \&... @@ -285,10 +288,24 @@ appended. .El .Pp Where sizes are specified, a decimal number of bytes is expected. -If the number ends with a ``b'', ``k'', ``m'' or ``w'', the number -is multiplied by 512, 1024 (1K), 1048576 (1M) or the number of bytes -in an integer, respectively. -Two or more numbers may be separated by an ``x'' to indicate a product. +Two or more numbers may be separated by an +.Dq x +to indicate a product. +Each number may have one of the following optional suffices: +.Bl -tag -width 3n -offset indent -compact +.It b +Block; multiply by 512 +.It k +Kilo; multiply by 1024 (1 KB) +.It m +Mega; multiply by 1048576 (1 MB) +.It g +Giga; multiply by 1073741824 (1 GB) +.It t +Tera; multiply by 1099511627776 (1 TB) +.It w +Word; multiply by the number of bytes in an integer +.El .Pp When finished, .Nm @@ -317,9 +334,12 @@ If .Nm receives a .Dv SIGINFO -(see the ``status'' argument for -.Xr stty 1 ) -signal, the current input and output block counts will +signal +(see the +.Ic status +argument for +.Xr stty 1 ) , +the current input and output block counts will be written to the standard error output in the same format as the standard completion message. If diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 1888e4d2e966..3be0614ac7f1 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -1,4 +1,4 @@ -/* $NetBSD: dd.c,v 1.22 2001/11/25 06:57:55 lukem Exp $ */ +/* $NetBSD: dd.c,v 1.23 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -47,7 +47,7 @@ __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\ #if 0 static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: dd.c,v 1.22 2001/11/25 06:57:55 lukem Exp $"); +__RCSID("$NetBSD: dd.c,v 1.23 2001/11/25 10:50:06 lukem Exp $"); #endif #endif /* not lint */ @@ -77,16 +77,16 @@ static void setup(void); int main(int, char *[]); -IO in, out; /* input/output state */ -STAT st; /* statistics */ -void (*cfunc)(void); /* conversion function */ -u_long cpy_cnt; /* # of blocks to copy */ -u_int ddflags; /* conversion options */ -u_int cbsz; /* conversion block size */ -u_int files_cnt = 1; /* # of files to copy */ -int progress = 0; /* display sign of life */ -const u_char *ctab; /* conversion table */ -sigset_t infoset; /* a set blocking SIGINFO */ +IO in, out; /* input/output state */ +STAT st; /* statistics */ +void (*cfunc)(void); /* conversion function */ +u_longlong_t cpy_cnt; /* # of blocks to copy */ +u_int ddflags; /* conversion options */ +u_longlong_t cbsz; /* conversion block size */ +u_int files_cnt = 1; /* # of files to copy */ +int progress = 0; /* display sign of life */ +const u_char *ctab; /* conversion table */ +sigset_t infoset; /* a set blocking SIGINFO */ int main(int argc, char *argv[]) @@ -243,7 +243,8 @@ getfdtype(IO *io) static void dd_in(void) { - int flags, n; + int flags; + u_longlong_t n; for (flags = ddflags;;) { if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) @@ -364,7 +365,7 @@ void dd_out(int force) { static int warned; - int cnt, n, nw; + u_longlong_t cnt, n, nw; u_char *outp; /* diff --git a/bin/dd/dd.h b/bin/dd/dd.h index e4a3f5fd6602..93497f216ea6 100644 --- a/bin/dd/dd.h +++ b/bin/dd/dd.h @@ -1,4 +1,4 @@ -/* $NetBSD: dd.h,v 1.7 2001/11/25 06:53:48 lukem Exp $ */ +/* $NetBSD: dd.h,v 1.8 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -41,37 +41,32 @@ /* Input/output stream state. */ typedef struct { - u_char *db; /* buffer address */ - u_char *dbp; /* current buffer I/O address */ - u_long dbcnt; /* current buffer byte count */ - int dbrcnt; /* last read byte count */ - u_long dbsz; /* buffer size */ + u_char *db; /* buffer address */ + u_char *dbp; /* current buffer I/O address */ + u_longlong_t dbcnt; /* current buffer byte count */ + u_longlong_t dbrcnt; /* last read byte count */ + u_longlong_t dbsz; /* buffer size */ #define ISCHR 0x01 /* character device (warn on short) */ #define ISPIPE 0x02 /* pipe (not truncatable) */ #define ISTAPE 0x04 /* tape (not seekable) */ #define NOREAD 0x08 /* not readable */ - u_int flags; + u_int flags; - const char *name; /* name */ - int fd; /* file descriptor */ - u_long offset; /* # of blocks to skip */ - - u_long f_stats; /* # of full blocks processed */ - u_long p_stats; /* # of partial blocks processed */ - u_long s_stats; /* # of odd swab blocks */ - u_long t_stats; /* # of truncations */ + const char *name; /* name */ + int fd; /* file descriptor */ + u_longlong_t offset; /* # of blocks to skip */ } IO; typedef struct { - u_long in_full; /* # of full input blocks */ - u_long in_part; /* # of partial input blocks */ - u_long out_full; /* # of full output blocks */ - u_long out_part; /* # of partial output blocks */ - u_long trunc; /* # of truncated records */ - u_long swab; /* # of odd-length swab blocks */ - u_quad_t bytes; /* # of bytes written */ - struct timeval start; /* start time of dd */ + u_longlong_t in_full; /* # of full input blocks */ + u_longlong_t in_part; /* # of partial input blocks */ + u_longlong_t out_full; /* # of full output blocks */ + u_longlong_t out_part; /* # of partial output blocks */ + u_longlong_t trunc; /* # of truncated records */ + u_longlong_t swab; /* # of odd-length swab blocks */ + u_longlong_t bytes; /* # of bytes written */ + struct timeval start; /* start time of dd */ } STAT; /* Flags (in ddflags). */ diff --git a/bin/dd/extern.h b/bin/dd/extern.h index 0dc0ce6a259e..333863e24556 100644 --- a/bin/dd/extern.h +++ b/bin/dd/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.11 2001/11/25 06:53:48 lukem Exp $ */ +/* $NetBSD: extern.h,v 1.12 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -56,16 +56,16 @@ void unblock(void); void unblock_close(void); ssize_t bwrite(int, const void *, size_t); -extern IO in, out; -extern STAT st; -extern void (*cfunc)(void); -extern u_long cpy_cnt; -extern u_int cbsz; -extern u_int ddflags; -extern u_int files_cnt; -extern int progress; -extern const u_char *ctab; -extern const u_char a2e_32V[], a2e_POSIX[]; -extern const u_char e2a_32V[], e2a_POSIX[]; -extern const u_char a2ibm_32V[], a2ibm_POSIX[]; -extern u_char casetab[]; +extern IO in, out; +extern STAT st; +extern void (*cfunc)(void); +extern u_longlong_t cpy_cnt; +extern u_longlong_t cbsz; +extern u_int ddflags; +extern u_int files_cnt; +extern int progress; +extern const u_char *ctab; +extern const u_char a2e_32V[], a2e_POSIX[]; +extern const u_char e2a_32V[], e2a_POSIX[]; +extern const u_char a2ibm_32V[], a2ibm_POSIX[]; +extern u_char casetab[]; diff --git a/bin/dd/misc.c b/bin/dd/misc.c index 6b6ffcc1d471..e2b19a22244f 100644 --- a/bin/dd/misc.c +++ b/bin/dd/misc.c @@ -1,4 +1,4 @@ -/* $NetBSD: misc.c,v 1.12 2001/11/25 06:53:48 lukem Exp $ */ +/* $NetBSD: misc.c,v 1.13 2001/11/25 10:50:06 lukem Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: misc.c,v 1.12 2001/11/25 06:53:48 lukem Exp $"); +__RCSID("$NetBSD: misc.c,v 1.13 2001/11/25 10:50:06 lukem Exp $"); #endif #endif /* not lint */ @@ -77,25 +77,28 @@ summary(void) mS = 1; /* Use snprintf(3) so that we don't reenter stdio(3). */ (void)snprintf(buf, sizeof(buf), - "%lu+%lu records in\n%lu+%lu records out\n", - st.in_full, st.in_part, st.out_full, st.out_part); + "%llu+%llu records in\n%llu+%llu records out\n", + (unsigned long long)st.in_full, (unsigned long long)st.in_part, + (unsigned long long)st.out_full, (unsigned long long)st.out_part); (void)write(STDERR_FILENO, buf, strlen(buf)); if (st.swab) { - (void)snprintf(buf, sizeof(buf), "%lu odd length swab %s\n", - st.swab, (st.swab == 1) ? "block" : "blocks"); + (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n", + (unsigned long long)st.swab, + (st.swab == 1) ? "block" : "blocks"); (void)write(STDERR_FILENO, buf, strlen(buf)); } if (st.trunc) { - (void)snprintf(buf, sizeof(buf), "%lu truncated %s\n", - st.trunc, (st.trunc == 1) ? "block" : "blocks"); + (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n", + (unsigned long long)st.trunc, + (st.trunc == 1) ? "block" : "blocks"); (void)write(STDERR_FILENO, buf, strlen(buf)); } (void)snprintf(buf, sizeof(buf), "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n", - (long long) st.bytes, + (unsigned long long) st.bytes, (long) (mS / 1000), (int) (mS % 1000), - (long long unsigned) (st.bytes * 1000LL / mS)); + (unsigned long long) (st.bytes * 1000LL / mS)); (void)write(STDERR_FILENO, buf, strlen(buf)); } diff --git a/bin/dd/strsuftoull.c b/bin/dd/strsuftoull.c new file mode 100644 index 000000000000..2ccc1642e10e --- /dev/null +++ b/bin/dd/strsuftoull.c @@ -0,0 +1,226 @@ +/* $NetBSD: strsuftoull.c,v 1.1 2001/11/25 10:50:06 lukem Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: strsuftoull.c,v 1.1 2001/11/25 10:50:06 lukem Exp $"); +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "strsuftoull.h" + + +/* + * Convert an expression of the following forms to a u_longlong_t. + * 1) A positive decimal number. + * 2) A positive decimal number followed by a b (mult by 512). + * 3) A positive decimal number followed by a k (mult by 1024). + * 4) A positive decimal number followed by a m (mult by 1048576). + * 5) A positive decimal number followed by a w (mult by sizeof int) + * 6) Two or more positive decimal numbers (with/without k,b or w). + * separated by x (also * for backwards compatibility), specifying + * the product of the indicated values. + * Returns the result upon successful conversion, or exits with an + * appropriate error. + * + */ +u_longlong_t +strsuftoull(const char *desc, const char *val, + u_longlong_t min, u_longlong_t max) +{ + u_longlong_t result; + char errbuf[100]; + + result = strsuftoullx(desc, val, min, max, errbuf, sizeof(errbuf)); + if (*errbuf != '\0') + errx(1, "%s", errbuf); + return (result); +} + +/* + * As strsuftoull(), but returns the error message into the provided buffer + * rather than exiting with it. + */ +u_longlong_t +strsuftoullx(const char *desc, const char *val, + u_longlong_t min, u_longlong_t max, char *ebuf, size_t ebuflen) +{ + u_longlong_t num, t; + char *expr; + + assert(desc != NULL); + assert(val != NULL); + assert(ebuf != NULL); + + errno = 0; + if (*val == '-') /* Prevent negative numbers */ + goto badnum; + + num = strtoull(val, &expr, 0); + if (num == LLONG_MAX && errno == ERANGE) + goto erange; /* Overflow */ + + if (expr == val) /* No digits */ + goto badnum; + + switch (*expr) { + case 'b': + t = num; + num *= 512; /* 1 block */ + if (t > num) + goto erange; + ++expr; + break; + case 'k': + t = num; + num *= 1024; /* 1 kilobyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'm': + t = num; + num *= 1048576; /* 1 megabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'g': + t = num; + num *= 1073741824; /* 1 gigabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 't': + t = num; + num *= 1099511627776; /* 1 terabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'w': + t = num; + num *= sizeof(int); /* 1 word */ + if (t > num) + goto erange; + ++expr; + break; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible */ + case 'x': + t = num; + num *= strsuftoullx(desc, expr + 1, min, max, ebuf, ebuflen); + if (*ebuf != '\0') + return (0); + if (t > num) { + erange: + snprintf(ebuf, ebuflen, + "%s: %s", desc, strerror(ERANGE)); + return (0); + } + break; + default: + badnum: snprintf(ebuf, ebuflen, + "%s `%s': illegal positive number", desc, val); + return (0); + } + if (num < min) { + snprintf(ebuf, ebuflen, + "%s %lld is less than %lld.", desc, num, min); + return (0); + } + if (num > max) { + snprintf(ebuf, ebuflen, + "%s %lld is greater than %lld.", desc, num, max); + return (0); + } + *ebuf = '\0'; + return (num); +} diff --git a/bin/dd/strsuftoull.h b/bin/dd/strsuftoull.h new file mode 100644 index 000000000000..45a641a77225 --- /dev/null +++ b/bin/dd/strsuftoull.h @@ -0,0 +1,7 @@ +/* $NetBSD: strsuftoull.h,v 1.1 2001/11/25 10:50:06 lukem Exp $ */ + +u_longlong_t strsuftoull(const char *, const char *, + u_longlong_t, u_longlong_t); + +u_longlong_t strsuftoullx(const char *, const char *, + u_longlong_t, u_longlong_t, char *, size_t);