Page MenuHomeFreeBSD

D51542.id159630.diff
No OneTemporary

D51542.id159630.diff

diff --git a/lib/libutil/expand_number.3 b/lib/libutil/expand_number.3
--- a/lib/libutil/expand_number.3
+++ b/lib/libutil/expand_number.3
@@ -1,5 +1,6 @@
.\" Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
.\" Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+.\" Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -23,43 +24,49 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 13, 2023
+.Dd July 25, 2025
.Dt EXPAND_NUMBER 3
.Os
.Sh NAME
.Nm expand_number
-.Nd format a number from human readable form
+.Nd parse a number from human readable form
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In libutil.h
.Ft int
.Fo expand_number
-.Fa "const char *buf" "uint64_t *num"
+.Fa "const char *buf" "int64_t *num"
.Fc
.Sh DESCRIPTION
The
.Fn expand_number
-function parses the
+function parses the number in the string pointed to by its
.Fa buf
-string and stores a unsigned 64-bit quantity at
-.Fa *num .
+argument and stores the number it represents as a signed 64-bit
+quantity in the location pointed to by its
+.Fa *num
+argument.
.Pp
-The
-.Fn expand_number
-function
-is case-insensitive and
-follows the SI power of two convention.
+The input string must consist of a decimal number, optionally preceded
+by a
+.Sq +
+or
+.Sq -
+sign, and optionally followed, without intervening whitespace, by a
+suffix indicating a power-of-two multiplier to apply.
+Any amount of whitespace at the beginning of the string will be
+ignored.
.Pp
-The suffixes are:
+Recognized suffixes are:
.Bl -column "Suffix" "Description" "1000000000000000000" -offset indent
.It Sy "Suffix" Ta Sy "Description" Ta Sy "Multiplier"
-.It Li K Ta No kilo Ta 1024
-.It Li M Ta No mega Ta 1048576
-.It Li G Ta No giga Ta 1073741824
-.It Li T Ta No tera Ta 1099511627776
-.It Li P Ta No peta Ta 1125899906842624
-.It Li E Ta No exa Ta 1152921504606846976
+.It Li K Ta No kilo Ta 1,024
+.It Li M Ta No mega Ta 1,048,576
+.It Li G Ta No giga Ta 1,073,741,824
+.It Li T Ta No tera Ta 1,099,511,627,776
+.It Li P Ta No peta Ta 1,125,899,906,842,624
+.It Li E Ta No exa Ta 1,152,921,504,606,846,976
.El
.Pp
For historical reasons, the
@@ -68,7 +75,11 @@
.Dq B
suffix at the end of the
.Fa buf
-string.
+string (i.e.
+.Dq 5b
+is interpreted as 5, and
+.Dq 5kb
+is interpreted as 5,120).
However, the usage of this suffix is discouraged.
.Sh RETURN VALUES
.Rv -std
@@ -78,11 +89,12 @@
function will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
-The given string contains no digits.
+The given string does not contain a valid number.
.It Bq Er EINVAL
-An unrecognized suffix was given.
+An unrecognized suffix was encountered.
.It Bq Er ERANGE
-Result doesn't fit into 64 bits.
+The given string represents a number which does not fit into a
+.Vt int64_t .
.El
.Sh SEE ALSO
.Xr humanize_number 3
diff --git a/lib/libutil/expand_number.c b/lib/libutil/expand_number.c
--- a/lib/libutil/expand_number.c
+++ b/lib/libutil/expand_number.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,79 +29,120 @@
*/
#include <sys/types.h>
+
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <libutil.h>
+#include <stdbool.h>
#include <stdint.h>
int
-expand_number(const char *buf, uint64_t *num)
+expand_number(const char *buf, int64_t *num)
{
char *endptr;
- uintmax_t umaxval;
- uint64_t number;
- unsigned shift;
+ uintmax_t number;
+ unsigned int shift;
+ bool neg;
int serrno;
+ /*
+ * Skip whitespace and optional sign.
+ */
+ while (isspace((unsigned char)*buf))
+ buf++;
+ if (*buf == '-') {
+ neg = true;
+ buf++;
+ } else {
+ neg = false;
+ if (*buf == '+')
+ buf++;
+ }
+
+ /*
+ * The next character should be the first digit of the number. If
+ * we don't enforce this ourselves, strtoumax() will allow further
+ * whitespace and a (second?) sign.
+ */
+ if (!isdigit((unsigned char)*buf)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
serrno = errno;
errno = 0;
- umaxval = strtoumax(buf, &endptr, 0);
- if (umaxval > UINT64_MAX)
- errno = ERANGE;
+ number = strtoumax(buf, &endptr, 0);
if (errno != 0)
return (-1);
errno = serrno;
- number = umaxval;
switch (tolower((unsigned char)*endptr)) {
case 'e':
shift = 60;
+ endptr++;
break;
case 'p':
shift = 50;
+ endptr++;
break;
case 't':
shift = 40;
+ endptr++;
break;
case 'g':
shift = 30;
+ endptr++;
break;
case 'm':
shift = 20;
+ endptr++;
break;
case 'k':
shift = 10;
+ endptr++;
break;
- case 'b':
- shift = 0;
- break;
- case '\0': /* No unit. */
- *num = number;
- return (0);
default:
- /* Unrecognized unit. */
- errno = EINVAL;
- return (-1);
+ shift = 0;
}
/*
* Treat 'b' as an ignored suffix for all unit except 'b',
* otherwise there should be no remaining character(s).
*/
- endptr++;
- if (shift != 0 && tolower((unsigned char)*endptr) == 'b')
+ if (tolower((unsigned char)*endptr) == 'b')
endptr++;
if (*endptr != '\0') {
errno = EINVAL;
return (-1);
}
+ /*
+ * Apply the shift and check for overflow.
+ */
if ((number << shift) >> shift != number) {
/* Overflow */
errno = ERANGE;
return (-1);
}
- *num = number << shift;
+ number <<= shift;
+
+ /*
+ * Apply the sign and check for overflow.
+ */
+ if (neg) {
+ if (number > 0x8000000000000000LLU /* -INT64_MIN */) {
+ errno = ERANGE;
+ return (-1);
+ }
+ *num = -number;
+ } else {
+ if (number > INT64_MAX) {
+ errno = ERANGE;
+ return (-1);
+ }
+ *num = number;
+ }
+
return (0);
}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -89,7 +89,7 @@
char *auth_getval(const char *_name);
void clean_environment(const char * const *_white,
const char * const *_more_white);
-int expand_number(const char *_buf, uint64_t *_num);
+int expand_number(const char *_buf, int64_t *_num);
int extattr_namespace_to_string(int _attrnamespace, char **_string);
int extattr_string_to_namespace(const char *_string, int *_attrnamespace);
int flopen(const char *_path, int _flags, ...);
diff --git a/usr.sbin/ctld/conf.cc b/usr.sbin/ctld/conf.cc
--- a/usr.sbin/ctld/conf.cc
+++ b/usr.sbin/ctld/conf.cc
@@ -409,7 +409,8 @@
bool
lun_set_device_type(const char *value)
{
- uint64_t device_type;
+ const char *errstr;
+ int device_type;
if (strcasecmp(value, "disk") == 0 ||
strcasecmp(value, "direct") == 0)
@@ -421,9 +422,12 @@
strcasecmp(value, "dvd") == 0 ||
strcasecmp(value, "dvdrom") == 0)
device_type = T_CDROM;
- else if (expand_number(value, &device_type) != 0 || device_type > 15) {
- log_warnx("invalid device-type \"%s\" for lun \"%s\"", value,
- lun->l_name);
+ else {
+ device_type = strtonum(value, 0, 15, &errstr);
+ if (errstr != NULL) {
+ log_warnx("invalid device-type \"%s\" for lun \"%s\"", value,
+ lun->l_name);
+ }
return (false);
}
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -105,7 +105,7 @@
debug: DEBUG STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -120,7 +120,7 @@
timeout: TIMEOUT STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -135,7 +135,7 @@
maxproc: MAXPROC STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -172,7 +172,7 @@
isns_period: ISNS_PERIOD STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -187,7 +187,7 @@
isns_timeout: ISNS_TIMEOUT STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -432,7 +432,7 @@
portal_group_tag: TAG STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -448,7 +448,7 @@
portal_group_dscp
: DSCP STR
{
- uint64_t tmp;
+ int64_t tmp;
if (strcmp($2, "0x") == 0) {
tmp = strtol($2 + 2, NULL, 16);
@@ -488,7 +488,7 @@
portal_group_pcp: PCP STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -704,7 +704,7 @@
lun_number: STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($1, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -720,7 +720,7 @@
target_lun_ref: LUN STR STR
{
- uint64_t tmp;
+ int64_t tmp;
bool ok;
if (expand_number($2, &tmp) != 0) {
@@ -778,7 +778,7 @@
lun_blocksize: BLOCKSIZE STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -816,7 +816,7 @@
lun_ctl_lun: CTL_LUN STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");
@@ -866,7 +866,7 @@
lun_size: SIZE STR
{
- uint64_t tmp;
+ int64_t tmp;
if (expand_number($2, &tmp) != 0) {
yyerror("invalid numeric value");

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 15, 4:24 PM (2 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29712669
Default Alt Text
D51542.id159630.diff (9 KB)

Event Timeline