diagnose too-large numbers better

Following on from commit v8.23-82-gaddae94, consistently diagnose
numbers that are too large, so as to distinguish from other errors,
and make the limits obvious.

* gl/modules/xdectoint: A new module implementing xdecto[iu]max(),
which handles the common case of parsing a bounded integer and
exiting with a diagnostic on error.
* gl/lib/xdectoimax.c: The signed variant.
* gl/lib/xdectoint.c: The parameterized implementation.
* gl/lib/xdectoint.h: The interface.
* gl/lib/xdectoumax.c: The unsigned variant.
* bootstrap.conf: Reference the new module.
* cfg.mk (exclude_file_name_regexp--sc_require_config_h_first):
Exclude the parameterized templates.
* src/csplit.c: Output EOVERFLOW or ERANGE errors if appropriate.
* src/fmt.c: Likewise.
* src/fold.c: Likewise.
* src/head.c: Likewise.
* src/ls.c: Likewise.
* src/nl.c: Likewise.
* src/nproc.c: Likewise.
* src/shred.c: Likewise.
* src/shuf.c: Likewise.
* src/stdbuf.c: Likewise.
* src/stty.c: Likewise.
* src/tail.c: Likewise.
* src/truncate.c: Likewise.
* src/split.c: Likewise.
* src/pr.c: Likewise.
* tests/pr/pr-tests.pl: Adjust to avoid matching errno diagnostic.
* tests/fmt/base.pl: Likewise.
* tests/split/l-chunk.sh: Likewise.
* tests/misc/shred-negative.sh: Likewise.
* tests/misc/tail.pl: Likewise.  Also remove the redundant
existing ERR_SUBST from test err-6.
* tests/ls/hex-option.sh: Check HEX/OCT options.
* tests/misc/shred-size.sh: Likewise.
* tests/misc/stty-row-col.sh: Likewise.
This commit is contained in:
Pádraig Brady
2014-12-16 12:36:39 +00:00
parent 178f8e79dc
commit 6894816c65
31 changed files with 367 additions and 369 deletions

View File

@@ -273,6 +273,7 @@ gnulib_modules="
xprintf
xprintf-posix
xreadlink
xdectoint
xstrtod
xstrtoimax
xstrtol

2
cfg.mk
View File

@@ -607,7 +607,7 @@ exclude_file_name_regexp--sc_system_h_headers = \
_src = (false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
exclude_file_name_regexp--sc_require_config_h_first = \
(^lib/buffer-lcm\.c|src/$(_src)\.c)$$
(^lib/buffer-lcm\.c|gl/lib/xdecto.max\.c|src/$(_src)\.c)$$
exclude_file_name_regexp--sc_require_config_h = \
$(exclude_file_name_regexp--sc_require_config_h_first)

6
gl/lib/xdectoimax.c Normal file
View File

@@ -0,0 +1,6 @@
#define __xdectoint xdectoimax
#define __xnumtoint xnumtoimax
#define __xdectoint_t intmax_t
#define __xstrtol xstrtoimax
#define __xdectoint_signed 1
#include "xdectoint.c"

85
gl/lib/xdectoint.c Normal file
View File

@@ -0,0 +1,85 @@
/* Convert decimal strings with bounds checking and exit on error.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "xdectoint.h"
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include "error.h"
#include "quote.h"
#include "xstrtol.h"
/* Parse numeric string N_STR of base BASE, and return the value.
Exit on parse error or if MIN or MAX are exceeded.
Strings can have multiplicative SUFFIXES if specified.
ERR is printed along with N_STR on error. */
__xdectoint_t
__xnumtoint (const char *n_str, int base, __xdectoint_t min, __xdectoint_t max,
const char *suffixes, const char *err, int err_exit)
{
strtol_error s_err;
__xdectoint_t tnum;
s_err = __xstrtol (n_str, NULL, base, &tnum, suffixes);
if (s_err == LONGINT_OK)
{
if (tnum < min || max < tnum)
{
s_err = LONGINT_OVERFLOW;
/* Use have the INT range as a heuristic to distinguish
type overflow rather than other min/max limits. */
if (tnum > INT_MAX/2)
errno = EOVERFLOW;
#if __xdectoint_signed
else if (tnum < INT_MIN/2)
errno = EOVERFLOW;
#endif
else
errno = ERANGE;
}
}
else if (s_err == LONGINT_OVERFLOW)
errno = EOVERFLOW;
else if (s_err == LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW)
errno = 0; /* Don't show ERANGE errors for invalid numbers. */
if (s_err != LONGINT_OK)
{
error (err_exit ? err_exit : EXIT_FAILURE, errno,
"%s: %s", err, quote (n_str));
}
return tnum;
}
/* Parse decimal string N_STR, and return the value.
Exit on parse error or if MIN or MAX are exceeded.
Strings can have multiplicative SUFFIXES if specified.
ERR is printed along with N_STR on error. */
__xdectoint_t
__xdectoint (const char *n_str, __xdectoint_t min, __xdectoint_t max,
const char *suffixes, const char *err, int err_exit)
{
return __xnumtoint (n_str, 10, min, max, suffixes, err, err_exit);
}

36
gl/lib/xdectoint.h Normal file
View File

@@ -0,0 +1,36 @@
/* Convert decimal strings with bounds checking and exit on error.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef XDECTOINT_H_
# define XDECTOINT_H_ 1
# include <inttypes.h>
# define _DECLARE_XDECTOINT(name, type) \
type name (const char *n_str, type min, type max, \
const char *suffixes, const char *err, int err_exit);
# define _DECLARE_XNUMTOINT(name, type) \
type name (const char *n_str, int base, type min, type max, \
const char *suffixes, const char *err, int err_exit);
_DECLARE_XDECTOINT (xdectoimax, intmax_t)
_DECLARE_XDECTOINT (xdectoumax, uintmax_t)
_DECLARE_XNUMTOINT (xnumtoimax, intmax_t)
_DECLARE_XNUMTOINT (xnumtoumax, uintmax_t)
#endif /* not XDECTOINT_H_ */

6
gl/lib/xdectoumax.c Normal file
View File

@@ -0,0 +1,6 @@
#define __xdectoint xdectoumax
#define __xnumtoint xnumtoumax
#define __xdectoint_t uintmax_t
#define __xstrtol xstrtoumax
#define __xdectoint_signed 0
#include "xdectoint.c"

29
gl/modules/xdectoint Normal file
View File

@@ -0,0 +1,29 @@
Description:
Convert decimal string to '[u]intmax_t', with bounds checking and exit on error
Files:
lib/xdectoint.h
lib/xdectoint.c
lib/xdectoimax.c
lib/xdectoumax.c
Depends-on:
error
errno
quote
xstrtoimax
xstrtoumax
configure.ac:
Makefile.am:
lib_SOURCES += xdectoimax.c xdectoumax.c
Include:
"xdectoint.h"
License:
GPL
Maintainer:
all

View File

@@ -33,6 +33,7 @@
#include "quote.h"
#include "safe-read.h"
#include "stdio--.h"
#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
@@ -1332,7 +1333,6 @@ int
main (int argc, char **argv)
{
int optc;
unsigned long int val;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -1366,10 +1366,8 @@ main (int argc, char **argv)
break;
case 'n':
if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
|| MIN (INT_MAX, SIZE_MAX) < val)
error (EXIT_FAILURE, 0, _("%s: invalid number"), optarg);
digits = val;
digits = xdectoimax (optarg, 0, MIN (INT_MAX, SIZE_MAX), "",
_("invalid number"), 0);
break;
case 's':

View File

@@ -1433,7 +1433,7 @@ scanargs (int argc, char *const *argv)
if (invalid != LONGINT_OK)
error (EXIT_FAILURE, invalid == LONGINT_OVERFLOW ? EOVERFLOW : 0,
_("invalid number %s"), quote (val));
"%s: %s", _("invalid number"), quote (val));
}
}

View File

@@ -30,7 +30,7 @@
#include "error.h"
#include "fadvise.h"
#include "quote.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "fmt"
@@ -399,23 +399,15 @@ main (int argc, char **argv)
{
/* Limit max_width to MAXCHARS / 2; otherwise, the resulting
output can be quite ugly. */
unsigned long int tmp;
if (! (xstrtoul (max_width_option, NULL, 10, &tmp, "") == LONGINT_OK
&& tmp <= MAXCHARS / 2))
error (EXIT_FAILURE, 0, _("invalid width: %s"),
quote (max_width_option));
max_width = tmp;
max_width = xdectoumax (max_width_option, 0, MAXCHARS / 2, "",
_("invalid width"), 0);
}
if (goal_width_option)
{
/* Limit goal_width to max_width. */
unsigned long int tmp;
if (! (xstrtoul (goal_width_option, NULL, 10, &tmp, "") == LONGINT_OK
&& tmp <= max_width))
error (EXIT_FAILURE, 0, _("invalid width: %s"),
quote (goal_width_option));
goal_width = tmp;
goal_width = xdectoumax (goal_width_option, 0, max_width, "",
_("invalid width"), 0);
if (max_width_option == NULL)
max_width = goal_width + 10;
}

View File

@@ -25,8 +25,7 @@
#include "system.h"
#include "error.h"
#include "fadvise.h"
#include "quote.h"
#include "xstrtol.h"
#include "xdectoint.h"
#define TAB_WIDTH 8
@@ -280,14 +279,8 @@ main (int argc, char **argv)
}
/* Fall through. */
case 'w': /* Line width. */
{
unsigned long int tmp_ulong;
if (! (xstrtoul (optarg, NULL, 10, &tmp_ulong, "") == LONGINT_OK
&& 0 < tmp_ulong && tmp_ulong < SIZE_MAX - TAB_WIDTH))
error (EXIT_FAILURE, 0,
_("invalid number of columns: %s"), quote (optarg));
width = tmp_ulong;
}
width = xdectoumax (optarg, 1, SIZE_MAX - TAB_WIDTH - 1, "",
_("invalid number of columns"), 0);
break;
case_GETOPT_HELP_CHAR;

View File

@@ -38,7 +38,7 @@
#include "safe-read.h"
#include "stat-size.h"
#include "xfreopen.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "head"
@@ -893,7 +893,7 @@ head_file (const char *filename, uintmax_t n_units, bool count_lines,
return ok;
}
/* Convert a string of decimal digits, N_STRING, with an optional suffinx
/* Convert a string of decimal digits, N_STRING, with an optional suffix
to an integral value. Upon successful conversion,
return that value. If it cannot be converted, give a diagnostic and exit.
COUNT_LINES indicates whether N_STRING is a number of bytes or a number
@@ -902,27 +902,9 @@ head_file (const char *filename, uintmax_t n_units, bool count_lines,
static uintmax_t
string_to_integer (bool count_lines, const char *n_string)
{
strtol_error s_err;
uintmax_t n;
s_err = xstrtoumax (n_string, NULL, 10, &n, "bkKmMGTPEZY0");
if (s_err == LONGINT_OVERFLOW)
{
error (EXIT_FAILURE, 0,
_("%s: %s is so large that it is not representable"), n_string,
count_lines ? _("number of lines") : _("number of bytes"));
}
if (s_err != LONGINT_OK)
{
error (EXIT_FAILURE, 0, "%s: %s", n_string,
(count_lines
? _("invalid number of lines")
: _("invalid number of bytes")));
}
return n;
return xdectoumax (n_string, 0, UINTMAX_MAX, "bkKmMGTPEZY0",
count_lines ? _("invalid number of lines")
: _("invalid number of bytes"), 0);
}
int
@@ -1076,8 +1058,8 @@ main (int argc, char **argv)
if ( ! count_lines && elide_from_end && OFF_T_MAX < n_units)
{
char umax_buf[INT_BUFSIZE_BOUND (n_units)];
error (EXIT_FAILURE, 0, _("%s: number of bytes is too large"),
umaxtostr (n_units, umax_buf));
error (EXIT_FAILURE, EOVERFLOW, "%s: %s", _("invalid number of bytes"),
quote (umaxtostr (n_units, umax_buf)));
}
file_list = (optind < argc

View File

@@ -105,6 +105,7 @@
#include "stat-size.h"
#include "stat-time.h"
#include "strftime.h"
#include "xdectoint.h"
#include "xstrtol.h"
#include "areadlink.h"
#include "mbsalign.h"
@@ -1742,15 +1743,9 @@ decode_switches (int argc, char **argv)
break;
case 'w':
{
unsigned long int tmp_ulong;
if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
|| ! (0 < tmp_ulong && tmp_ulong <= SIZE_MAX))
error (LS_FAILURE, 0, _("invalid line width: %s"),
quotearg (optarg));
line_length = tmp_ulong;
break;
}
line_length = xnumtoumax (optarg, 0, 1, SIZE_MAX, "",
_("invalid line width"), LS_FAILURE);
break;
case 'x':
format = horizontal;
@@ -1816,15 +1811,9 @@ decode_switches (int argc, char **argv)
break;
case 'T':
{
unsigned long int tmp_ulong;
if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
|| SIZE_MAX < tmp_ulong)
error (LS_FAILURE, 0, _("invalid tab size: %s"),
quotearg (optarg));
tabsize = tmp_ulong;
break;
}
tabsize = xnumtoumax (optarg, 0, 0, SIZE_MAX, "",
_("invalid tab size"), LS_FAILURE);
break;
case 'U':
sort_type = sort_none;

View File

@@ -31,7 +31,7 @@
#include "fadvise.h"
#include "linebuffer.h"
#include "quote.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "nl"
@@ -497,53 +497,27 @@ main (int argc, char **argv)
}
break;
case 'v':
if (xstrtoimax (optarg, NULL, 10, &starting_line_number, "")
!= LONGINT_OK)
{
error (0, 0, _("invalid starting line number: %s"),
quote (optarg));
ok = false;
}
starting_line_number = xdectoimax (optarg, INTMAX_MIN, INTMAX_MAX, "",
_("invalid starting line number"),
0);
break;
case 'i':
if (! (xstrtoimax (optarg, NULL, 10, &page_incr, "") == LONGINT_OK
&& 0 < page_incr))
{
error (0, 0, _("invalid line number increment: %s"),
quote (optarg));
ok = false;
}
page_incr = xdectoimax (optarg, 1, INTMAX_MAX, "",
_("invalid line number increment"), 0);
break;
case 'p':
reset_numbers = false;
break;
case 'l':
if (! (xstrtoimax (optarg, NULL, 10, &blank_join, "") == LONGINT_OK
&& 0 < blank_join))
{
error (0, 0, _("invalid number of blank lines: %s"),
quote (optarg));
ok = false;
}
blank_join = xdectoimax (optarg, 1, INTMAX_MAX, "",
_("invalid line number of blank lines"), 0);
break;
case 's':
separator_str = optarg;
break;
case 'w':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
{
error (0, 0, _("invalid line number field width: %s"),
quote (optarg));
ok = false;
}
else
{
lineno_width = tmp_long;
}
}
lineno_width = xdectoimax (optarg, 1, INT_MAX, "",
_("invalid line number field width"), 0);
break;
case 'n':
if (STREQ (optarg, "ln"))

View File

@@ -25,7 +25,7 @@
#include "error.h"
#include "nproc.h"
#include "quote.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "nproc"
@@ -102,11 +102,7 @@ main (int argc, char **argv)
break;
case IGNORE_OPTION:
if (xstrtoul (optarg, NULL, 10, &ignore, "") != LONGINT_OK)
{
error (0, 0, _("%s: invalid number to ignore"), optarg);
usage (EXIT_FAILURE);
}
ignore = xdectoumax (optarg, 0, ULONG_MAX, "", _("invalid number"),0);
break;
default:

View File

@@ -322,6 +322,7 @@
#include "stdio--.h"
#include "strftime.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "pr"
@@ -424,6 +425,8 @@ static bool skip_to_page (uintmax_t page);
static void print_header (void);
static void pad_across_to (int position);
static void add_line_number (COLUMN *p);
static void getoptnum (const char *n_str, int min, int *num,
const char *errfmt);
static void getoptarg (char *arg, char switch_char, char *character,
int *number);
static void print_files (int number_of_files, char **av);
@@ -820,18 +823,12 @@ first_last_page (int oi, char c, char const *pages)
/* Parse column count string S, and if it's valid (1 or larger and
within range of the type of 'columns') set the global variables
columns and explicit_columns and return true.
Otherwise, exit with a diagnostic. */
columns and explicit_columns. Otherwise, exit with a diagnostic. */
static void
parse_column_count (char const *s)
{
long int tmp_long;
if (xstrtol (s, NULL, 10, &tmp_long, "") != LONGINT_OK
|| !(1 <= tmp_long && tmp_long <= INT_MAX))
error (EXIT_FAILURE, 0,
_("invalid number of columns: %s"), quote (s));
columns = tmp_long;
getoptnum (s, 1, &columns, _("invalid number of columns"));
explicit_columns = true;
}
@@ -966,18 +963,9 @@ main (int argc, char **argv)
join_lines = true;
break;
case 'l':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
{
error (EXIT_FAILURE, 0,
_("'-l PAGE_LENGTH' invalid number of lines: %s"),
quote (optarg));
}
lines_per_page = tmp_long;
break;
}
getoptnum (optarg, 1, &lines_per_page,
_("'-l PAGE_LENGTH' invalid number of lines"));
break;
case 'm':
parallel_files = true;
storing_columns = false;
@@ -990,28 +978,13 @@ main (int argc, char **argv)
break;
case 'N':
skip_count = false;
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long > INT_MAX)
{
error (EXIT_FAILURE, 0,
_("'-N NUMBER' invalid starting line number: %s"),
quote (optarg));
}
start_line_num = tmp_long;
break;
}
getoptnum (optarg, INT_MIN, &start_line_num,
_("'-N NUMBER' invalid starting line number"));
break;
case 'o':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0,
_("'-o MARGIN' invalid line offset: %s"), quote (optarg));
chars_per_margin = tmp_long;
break;
}
getoptnum (optarg, 0, &chars_per_margin,
_("'-o MARGIN' invalid line offset"));
break;
case 'r':
ignore_failed_opens = true;
break;
@@ -1045,29 +1018,19 @@ main (int argc, char **argv)
old_options = true;
old_w = true;
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0,
_("'-w PAGE_WIDTH' invalid number of characters: %s"),
quote (optarg));
if (!truncate_lines)
chars_per_line = tmp_long;
break;
int tmp_cpl;
getoptnum (optarg, 1, &tmp_cpl,
_("'-w PAGE_WIDTH' invalid number of characters"));
if (! truncate_lines)
chars_per_line = tmp_cpl;
}
break;
case 'W':
old_w = false; /* dominates -w */
truncate_lines = true;
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0,
_("'-W PAGE_WIDTH' invalid number of characters: %s"),
quote (optarg));
chars_per_line = tmp_long;
break;
}
getoptnum (optarg, 1, &chars_per_line,
_("'-W PAGE_WIDTH' invalid number of characters"));
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
@@ -1173,6 +1136,15 @@ main (int argc, char **argv)
return failed_opens ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Parse numeric arguments, ensuring MIN <= number <= INT_MAX. */
static void
getoptnum (const char *n_str, int min, int *num, const char *err)
{
intmax_t tnum = xdectoimax (n_str, min, INT_MAX, "", err, 0);
*num = tnum;
}
/* Parse options of the form -scNNN.
Example: -nck, where 'n' is the option, c is the optional number
@@ -1188,9 +1160,9 @@ getoptarg (char *arg, char switch_char, char *character, int *number)
{
long int tmp_long;
if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
|| tmp_long <= 0 || INT_MAX < tmp_long)
{
error (0, 0,
error (0, INT_MAX < tmp_long ? EOVERFLOW : errno,
_("'-%c' extra characters or invalid number in the argument: %s"),
switch_char, quote (arg));
usage (EXIT_FAILURE);

View File

@@ -86,7 +86,7 @@
#include "system.h"
#include "argmatch.h"
#include "xstrtol.h"
#include "xdectoint.h"
#include "error.h"
#include "fcntl--.h"
#include "human.h"
@@ -1228,16 +1228,10 @@ main (int argc, char **argv)
break;
case 'n':
{
uintmax_t tmp;
if (xstrtoumax (optarg, NULL, 10, &tmp, NULL) != LONGINT_OK
|| MIN (ULONG_MAX, SIZE_MAX / sizeof (int)) <= tmp)
{
error (EXIT_FAILURE, 0, _("%s: invalid number of passes"),
quotearg_colon (optarg));
}
flags.n_iterations = tmp;
}
flags.n_iterations = xdectoumax (optarg, 0,
MIN (ULONG_MAX,
SIZE_MAX / sizeof (int)), "",
_("invalid number of passes"), 0);
break;
case RANDOM_SOURCE_OPTION:
@@ -1255,17 +1249,8 @@ main (int argc, char **argv)
break;
case 's':
{
uintmax_t tmp;
if ((xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0")
!= LONGINT_OK)
|| OFF_T_MAX < tmp)
{
error (EXIT_FAILURE, 0, _("%s: invalid file size"),
quotearg_colon (optarg));
}
flags.size = tmp;
}
flags.size = xnumtoumax (optarg, 0, 0, OFF_T_MAX, "cbBkKMGTPEZY0",
_("invalid file size"), 0);
break;
case 'v':

View File

@@ -32,6 +32,7 @@
#include "randperm.h"
#include "read-file.h"
#include "stdio--.h"
#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
@@ -422,7 +423,6 @@ main (int argc, char **argv)
case 'i':
{
unsigned long int argval = 0;
char *p = strchr (optarg, '-');
char const *hi_optarg = optarg;
bool invalid = !p;
@@ -434,22 +434,19 @@ main (int argc, char **argv)
if (p)
{
*p = '\0';
invalid = ((xstrtoul (optarg, NULL, 10, &argval, NULL)
!= LONGINT_OK)
|| SIZE_MAX < argval);
lo_input = xdectoumax (optarg, 0, SIZE_MAX, "",
_("invalid input range"), 0);
*p = '-';
lo_input = argval;
hi_optarg = p + 1;
}
invalid |= ((xstrtoul (hi_optarg, NULL, 10, &argval, NULL)
!= LONGINT_OK)
|| SIZE_MAX < argval);
hi_input = argval;
hi_input = xdectoumax (hi_optarg, 0, SIZE_MAX, "",
_("invalid input range"), 0);
n_lines = hi_input - lo_input + 1;
invalid |= ((lo_input <= hi_input) == (n_lines == 0));
if (invalid)
error (EXIT_FAILURE, 0, _("invalid input range %s"),
error (EXIT_FAILURE, errno, "%s: %s", _("invalid input range"),
quote (optarg));
}
break;
@@ -462,7 +459,7 @@ main (int argc, char **argv)
if (e == LONGINT_OK)
head_lines = MIN (head_lines, argval);
else if (e != LONGINT_OVERFLOW)
error (EXIT_FAILURE, 0, _("invalid line count %s"),
error (EXIT_FAILURE, 0, _("invalid line count: %s"),
quote (optarg));
}
break;

View File

@@ -39,7 +39,7 @@
#include "safe-read.h"
#include "sig2str.h"
#include "xfreopen.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "split"
@@ -1174,19 +1174,20 @@ no_filters:
} \
while (0)
/* Parse K/N syntax of chunk options. */
static void
parse_chunk (uintmax_t *k_units, uintmax_t *n_units, char *slash)
{
*slash = '\0';
if (xstrtoumax (slash + 1, NULL, 10, n_units, "") != LONGINT_OK
|| *n_units == 0)
error (EXIT_FAILURE, 0, _("%s: invalid number of chunks"), slash + 1);
if (slash != optarg /* a leading number is specified. */
&& (xstrtoumax (optarg, NULL, 10, k_units, "") != LONGINT_OK
|| *k_units == 0 || *n_units < *k_units))
error (EXIT_FAILURE, 0, _("%s: invalid chunk number"), optarg);
*n_units = xdectoumax (slash + 1, 1, UINTMAX_MAX, "",
_("invalid number of chunks"), 0);
if (slash != optarg) /* a leading number is specified. */
{
*slash = '\0';
*k_units = xdectoumax (optarg, 1, *n_units, "",
_("invalid chunk number"), 0);
}
}
@@ -1197,7 +1198,7 @@ main (int argc, char **argv)
size_t in_blk_size = 0; /* optimal block size of input file device */
size_t page_size = getpagesize ();
uintmax_t k_units = 0;
uintmax_t n_units;
uintmax_t n_units = 0;
static char const multipliers[] = "bEGKkMmPTYZ0";
int c;
@@ -1231,16 +1232,8 @@ main (int argc, char **argv)
switch (c)
{
case 'a':
{
unsigned long tmp;
if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
|| SIZE_MAX / sizeof (size_t) < tmp)
{
error (0, 0, _("%s: invalid suffix length"), optarg);
usage (EXIT_FAILURE);
}
suffix_length = tmp;
}
suffix_length = xdectoumax (optarg, 0, SIZE_MAX / sizeof (size_t),
"", _("invalid suffix length"), 0);
break;
case ADDITIONAL_SUFFIX_OPTION:
@@ -1258,46 +1251,27 @@ main (int argc, char **argv)
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_bytes;
if (xstrtoumax (optarg, NULL, 10, &n_units, multipliers) != LONGINT_OK
|| n_units == 0)
{
error (0, 0, _("%s: invalid number of bytes"), optarg);
usage (EXIT_FAILURE);
}
/* If input is a pipe, we could get more data than is possible
to write to a single file, so indicate that immediately
rather than having possibly future invocations fail. */
if (OFF_T_MAX < n_units)
error (EXIT_FAILURE, EFBIG,
_("%s: invalid number of bytes"), optarg);
/* Limit to OFF_T_MAX, becaue if input is a pipe, we could get more
data than is possible to write to a single file, so indicate that
immediately rather than having possibly future invocations fail. */
n_units = xdectoumax (optarg, 1, OFF_T_MAX, multipliers,
_("invalid number of bytes"), 0);
break;
case 'l':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_lines;
if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
|| n_units == 0)
{
error (0, 0, _("%s: invalid number of lines"), optarg);
usage (EXIT_FAILURE);
}
n_units = xdectoumax (optarg, 1, UINTMAX_MAX, "",
_("invalid number of lines"), 0);
break;
case 'C':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_byteslines;
if (xstrtoumax (optarg, NULL, 10, &n_units, multipliers) != LONGINT_OK
|| n_units == 0 || SIZE_MAX < n_units)
{
error (0, 0, _("%s: invalid number of bytes"), optarg);
usage (EXIT_FAILURE);
}
if (OFF_T_MAX < n_units)
error (EXIT_FAILURE, EFBIG,
_("%s: invalid number of bytes"), optarg);
n_units = xdectoumax (optarg, 1, MIN (SIZE_MAX, OFF_T_MAX),
multipliers, _("invalid number of bytes"), 0);
break;
case 'n':
@@ -1320,9 +1294,9 @@ main (int argc, char **argv)
split_type = type_chunk_bytes;
if ((slash = strchr (optarg, '/')))
parse_chunk (&k_units, &n_units, slash);
else if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
|| n_units == 0)
error (EXIT_FAILURE, 0, _("%s: invalid number of chunks"), optarg);
else
n_units = xdectoumax (optarg, 1, UINTMAX_MAX, "",
_("invalid number of chunks"), 0);
break;
case 'u':
@@ -1388,15 +1362,8 @@ main (int argc, char **argv)
break;
case IO_BLKSIZE_OPTION:
{
uintmax_t tmp_blk_size;
if (xstrtoumax (optarg, NULL, 10, &tmp_blk_size,
multipliers) != LONGINT_OK
|| tmp_blk_size == 0 || SIZE_MAX - page_size < tmp_blk_size)
error (0, 0, _("%s: invalid IO block size"), optarg);
else
in_blk_size = tmp_blk_size;
}
in_blk_size = xdectoumax (optarg, 1, SIZE_MAX - page_size,
multipliers, _("invalid IO block size"), 0);
break;
case VERBOSE_OPTION:
@@ -1427,7 +1394,7 @@ main (int argc, char **argv)
if (n_units == 0)
{
error (0, 0, _("%s: invalid number of lines"), "0");
error (0, 0, "%s: %s", _("invalid number of lines"), quote ("0"));
usage (EXIT_FAILURE);
}
@@ -1505,8 +1472,9 @@ main (int argc, char **argv)
if (OFF_T_MAX < n_units)
{
char buffer[INT_BUFSIZE_BOUND (uintmax_t)];
error (EXIT_FAILURE, EFBIG, _("%s: invalid number of chunks"),
umaxtostr (n_units, buffer));
error (EXIT_FAILURE, EOVERFLOW, "%s: %s",
_("invalid number of chunks"),
quote (umaxtostr (n_units, buffer)));
}
/* increase file_size to n_units here, so that we still process
any input data, and create empty files for the rest. */

View File

@@ -66,7 +66,7 @@ parse_size (char const *str, size_t *size)
{
uintmax_t tmp_size;
enum strtol_error e = xstrtoumax (str, NULL, 10, &tmp_size, "EGkKMPTYZ0");
if (e == LONGINT_OK && tmp_size > SIZE_MAX)
if (e == LONGINT_OK && SIZE_MAX < tmp_size)
e = LONGINT_OVERFLOW;
if (e == LONGINT_OK)
@@ -76,7 +76,7 @@ parse_size (char const *str, size_t *size)
return 0;
}
errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : 0);
errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : errno);
return -1;
}

View File

@@ -58,6 +58,7 @@
#include "error.h"
#include "fd-reopen.h"
#include "quote.h"
#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
@@ -2087,11 +2088,5 @@ visible (cc_t ch)
static unsigned long int
integer_arg (const char *s, unsigned long int maxval)
{
unsigned long int value;
if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
{
error (0, 0, _("invalid integer argument %s"), quote (s));
usage (EXIT_FAILURE);
}
return value;
return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"), 0);
}

View File

@@ -44,6 +44,7 @@
#include "stat-time.h"
#include "xfreopen.h"
#include "xnanosleep.h"
#include "xdectoint.h"
#include "xstrtol.h"
#include "xstrtod.h"
@@ -1949,7 +1950,10 @@ parse_obsolete_option (int argc, char * const *argv, uintmax_t *n_units)
else if ((xstrtoumax (n_string, NULL, 10, n_units, "b")
& ~LONGINT_INVALID_SUFFIX_CHAR)
!= LONGINT_OK)
error (EXIT_FAILURE, 0, _("number in %s is too large"), quote (argv[1]));
{
error (EXIT_FAILURE, errno, "%s: %s", _("invalid number"),
quote (argv[1]));
}
/* Set globals. */
from_start = t_from_start;
@@ -1986,17 +1990,10 @@ parse_options (int argc, char **argv,
else if (*optarg == '-')
++optarg;
{
strtol_error s_err;
s_err = xstrtoumax (optarg, NULL, 10, n_units, "bkKmMGTPEZY0");
if (s_err != LONGINT_OK)
{
error (EXIT_FAILURE, 0, "%s: %s", optarg,
(c == 'n'
? _("invalid number of lines")
: _("invalid number of bytes")));
}
}
*n_units = xdectoumax (optarg, 0, UINTMAX_MAX, "bkKmMGTPEZY0",
count_lines
? _("invalid number of lines")
: _("invalid number of bytes"), 0);
break;
case 'f':
@@ -2015,15 +2012,9 @@ parse_options (int argc, char **argv,
case MAX_UNCHANGED_STATS_OPTION:
/* --max-unchanged-stats=N */
if (xstrtoumax (optarg, NULL, 10,
&max_n_unchanged_stats_between_opens,
"")
!= LONGINT_OK)
{
error (EXIT_FAILURE, 0,
_("%s: invalid maximum number of unchanged stats between opens"),
optarg);
}
max_n_unchanged_stats_between_opens =
xdectoumax (optarg, 0, UINTMAX_MAX, "",
_("invalid maximum number of unchanged stats between opens"), 0);
break;
case DISABLE_INOTIFY_OPTION:
@@ -2031,16 +2022,7 @@ parse_options (int argc, char **argv,
break;
case PID_OPTION:
{
strtol_error s_err;
unsigned long int tmp_ulong;
s_err = xstrtoul (optarg, NULL, 10, &tmp_ulong, "");
if (s_err != LONGINT_OK || tmp_ulong > PID_T_MAX)
{
error (EXIT_FAILURE, 0, _("%s: invalid PID"), optarg);
}
pid = tmp_ulong;
}
pid = xdectoumax (optarg, 0, PID_T_MAX, "", _("invalid PID"), 0);
break;
case PRESUME_INPUT_PIPE_OPTION:
@@ -2056,7 +2038,7 @@ parse_options (int argc, char **argv,
double s;
if (! (xstrtod (optarg, NULL, &s, c_strtod) && 0 <= s))
error (EXIT_FAILURE, 0,
_("%s: invalid number of seconds"), optarg);
_("invalid number of seconds: %s"), quote (optarg));
*sleep_interval = s;
}
break;

View File

@@ -29,7 +29,7 @@
#include "error.h"
#include "quote.h"
#include "stat-size.h"
#include "xstrtol.h"
#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "truncate"
@@ -59,33 +59,6 @@ static struct option const longopts[] =
typedef enum
{ rm_abs = 0, rm_rel, rm_min, rm_max, rm_rdn, rm_rup } rel_mode_t;
/* Set size to the value of STR, interpreted as a decimal integer,
optionally multiplied by various values.
Return -1 on error, 0 on success.
This supports dd BLOCK size suffixes + lowercase g,t,m for bsd compat
Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats. */
static int
parse_len (char const *str, off_t *size)
{
enum strtol_error e;
intmax_t tmp_size;
e = xstrtoimax (str, NULL, 10, &tmp_size, "EgGkKmMPtTYZ0");
if (e == LONGINT_OK
&& !(OFF_T_MIN <= tmp_size && tmp_size <= OFF_T_MAX))
e = LONGINT_OVERFLOW;
if (e == LONGINT_OK)
{
errno = 0;
*size = tmp_size;
return 0;
}
errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : 0);
return -1;
}
void
usage (int status)
{
@@ -306,9 +279,10 @@ main (int argc, char **argv)
}
rel_mode = rm_rel;
}
if (parse_len (optarg, &size) == -1)
error (EXIT_FAILURE, errno, _("invalid number %s"),
quote (optarg));
/* Support dd BLOCK size suffixes + lowercase g,t,m for bsd compat.
Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats. */
size = xdectoimax (optarg, OFF_T_MIN, OFF_T_MAX, "EgGkKmMPtTYZ0",
_("Invalid number"), 0);
/* Rounding to multiple of 0 is nonsensical */
if ((rel_mode == rm_rup || rel_mode == rm_rdn) && size == 0)
error (EXIT_FAILURE, 0, _("division by zero"));

View File

@@ -26,9 +26,11 @@ my @Tests =
{IN=> "ça\nçb\n"},
{OUT=>"ça b\n"}],
['wide-1', '-w 32768',
{ERR => "fmt: invalid width: '32768'\n"}, {EXIT => 1}],
{ERR => "fmt: invalid width: '32768'"}, {EXIT => 1},
{ERR_SUBST => 's/:[^:]*$//'}],
['wide-2', '-w 2147483647',
{ERR => "fmt: invalid width: '2147483647'\n"}, {EXIT => 1}],
{ERR => "fmt: invalid width: '2147483647'"}, {EXIT => 1},
{ERR_SUBST => 's/:[^:]*$//'}],
['bad-suffix', '-72x', {IN=> ''},
{ERR => "fmt: invalid width: '72x'\n"}, {EXIT => 1}],
['no-file', 'no-such-file',

View File

@@ -320,9 +320,9 @@ all_tests = \
tests/misc/sha384sum.pl \
tests/misc/sha512sum.pl \
tests/misc/shred-exact.sh \
tests/misc/shred-negative.sh \
tests/misc/shred-passes.sh \
tests/misc/shred-remove.sh \
tests/misc/shred-size.sh \
tests/misc/shuf.sh \
tests/misc/shuf-reservoir.sh \
tests/misc/sort.pl \
@@ -557,6 +557,7 @@ all_tests = \
tests/ls/file-type.sh \
tests/ls/follow-slink.sh \
tests/ls/getxattr-speedup.sh \
tests/ls/hex-option.sh \
tests/ls/infloop.sh \
tests/ls/inode.sh \
tests/ls/m-option.sh \

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Exercise shred -s-3 FILE
# accept hex/oct numbers to -w and -T
# Copyright (C) 2014 Free Software Foundation, Inc.
@@ -17,12 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ shred
print_ver_ ls
echo 'shred: -2: invalid file size' > exp || framework_failure_
echo 1234 > f || framework_failure_
shred -s-2 f 2>err && fail=1
compare exp err || fail=1
ls -x -T0x10 -w010 || fail=1
Exit $fail

34
tests/misc/shred-size.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
# Exercise shred --size
# Copyright (C) 2014 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ shred
# Negative size
echo "shred: invalid file size: '-2'" > exp || framework_failure_
echo 1234 > f || framework_failure_
shred -s-2 f 2>err && fail=1
compare exp err || fail=1
# Octal/Hex
shred -s010 f || fail=1
test $(stat --printf=%s f) = 8 || fail=1
shred -s0x10 f || fail=1
test $(stat --printf=%s f) = 16 || fail=1
Exit $fail

View File

@@ -47,6 +47,8 @@ tests='
7 rows_1 1_1
8 columns_80 1_80
9 rows_30 30_80
10 rows_0x1E 30_80
11 rows_036 30_80
NA LAST NA
'
set $tests

View File

@@ -19,7 +19,7 @@
use strict;
my $prog = 'tail';
my $normalize_filename = {ERR_SUBST => 's/^$prog: .*?:/$prog: -:/'};
my $normalize_strerror = 's/:[^:]*$//';
# Turn off localization of executable's output.
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
@@ -59,7 +59,7 @@ my @tv = (
"$prog: cannot open '+cl' for reading: No such file or directory\n"],
['err-2', '-cl', '', '', 1,
"$prog: l: invalid number of bytes\n"],
"$prog: invalid number of bytes: 'l'\n"],
['err-3', '+2cz', '', '', 1,
"$prog: cannot open '+2cz' for reading: No such file or directory\n"],
@@ -72,9 +72,9 @@ my @tv = (
# the diagnostic: 'tail: 99999999999999999999: invalid number of bytes'
# on all systems... probably, for now, maybe.
['err-5', '-c99999999999999999999', '', '', 1,
"$prog: 99999999999999999999: invalid number of bytes\n"],
"$prog: invalid number of bytes: '99999999999999999999'", $normalize_strerror],
['err-6', '-c --', '', '', 1,
"$prog: -: invalid number of bytes\n", $normalize_filename],
"$prog: invalid number of bytes: '-'\n"],
# Same as -n 10
['minus-1', '-', '', '', 0],
@@ -106,10 +106,10 @@ my @Tests;
foreach my $t (@tv)
{
my ($test_name, $flags, $in, $exp, $ret, $err_msg) = @$t;
my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
my $e = [$test_name, $flags, {IN=>$in}, {OUT=>$exp}];
$ret
and push @$e, {EXIT=>$ret}, {ERR=>$err_msg};
and push @$e, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
$test_name =~ /^(obs-plus-|minus-)/
and push @$e, {ENV=>'_POSIX2_VERSION=199209'};

View File

@@ -385,9 +385,11 @@ my @tv = (
['col-long', '-W3 -t -1 --columns=2', "a\nb\nc\n", "a c\nb\n", 0],
# Make sure these fail.
['col-0', '-0', '', '', 1,
"$prog: invalid number of columns: '0'\n"],
"$prog: invalid number of columns: '0'",
's/:[^:]*$//'],
['col-inval', '-'.'9'x100, '', '', 1,
"$prog: invalid number of columns: '". ('9'x100) ."'\n"],
"$prog: invalid number of columns: '". ('9'x100) ."'",
's/:[^:]*$//'],
# Before coreutils-5.3.1, --pages=1:-1 would be treated like
# --pages=1:18446744073709551615.
@@ -427,7 +429,7 @@ my $common_option_prefix = '--date-format="-- Date/Time --" -h x';
my @Tests;
foreach my $t (@tv)
{
my ($test_name, $flags, $in, $exp, $ret, $err_msg) = @$t;
my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
my $new_ent = [$test_name, $common_option_prefix, $flags];
if (!ref $in)
{
@@ -454,7 +456,7 @@ foreach my $t (@tv)
}
}
$ret
and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg};
and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
push @Tests, $new_ent;
}

View File

@@ -20,7 +20,7 @@
print_ver_ split
# invalid number of chunks
echo 'split: 1o: invalid number of chunks' > exp
echo "split: invalid number of chunks: '1o'" > exp
split -n l/1o 2>err && fail=1
compare exp err || fail=1
@@ -53,8 +53,9 @@ lines=\
printf "%s" "$lines" | tr '~' '\n' > in || framework_failure_
echo 'split: 16: invalid chunk number' > exp
split -n l/16/15 in 2>err && fail=1
echo "split: invalid chunk number: '16'" > exp
split -n l/16/15 in 2>err.t && fail=1
sed 's/:[^:]*$//' < err.t > err || framework_failure_
compare exp err || fail=1
printf '%s' "\