#include <freeradius-devel/server/dependency.h>
#include <freeradius-devel/server/map_proc.h>
#include <freeradius-devel/server/module.h>
-#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/server/radmin.h>
#include <freeradius-devel/server/state.h>
#include <freeradius-devel/server/virtual_servers.h>
+#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/size.h>
#include <freeradius-devel/tls/base.h>
#include <freeradius-devel/tls/log.h>
*/
env = getenv("FR_GLOBAL_POOL");
if (env) {
- if (fr_size_from_str(&pool_size, env) < 0) {
+ if (fr_size_from_str(&pool_size, &FR_SBUFF_IN(env, strlen(env))) < 0) {
fr_perror("Invalid pool size string \"%s\"", env);
EXIT_WITH_FAILURE;
}
if (cf_pair_to_value_box(ctx, &vb, cf_item_to_pair(ci), rule) < 0) goto error;
if (fr_value_box_memcpy_out(out, &vb) < 0) {
+ cf_log_perr(cp, "Failed unboxing parsed configuration item value");
fr_value_box_clear_value(&vb);
goto error;
}
sbuff.c \
sem.c \
sha1.c \
+ size.c \
snprintf.c \
socket.c \
strerror.c \
return strlcpy(out, p, outlen);
}
-int fr_size_from_str(size_t *out, char const *str)
-{
- char *q = NULL;
- uint64_t size;
-
- *out = 0;
-
- size = strtoull(str, &q, 10);
- switch (tolower(q[0])) {
- case 'n': /* nibble */
- if (size & 0x01) {
- fr_strerror_const("Sizes specified in nibbles must be an even number");
- return -1;
- }
- size /= 2;
- break;
-
- case '\0':
- case 'b': /* byte */
- break;
-
- case 'k': /* kilobyte */
- if (!fr_multiply(&size, size, 1024)) {
- overflow:
- fr_strerror_printf("Value must be less than %zu", (size_t)SIZE_MAX);
- return -1;
- }
- break;
-
- case 'm': /* megabyte */
- if (!fr_multiply(&size, size, (1024 * 1024))) goto overflow;
- break;
-
- case 'g': /* gigabyte */
- if (!fr_multiply(&size, size, (1024 * 1024 * 1024))) goto overflow;
- break;
-
- case 't': /* terabyte */
- if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024 * 1024 * 1024))) goto overflow;
- break;
-
- default:
- fr_strerror_printf("Unknown unit '%c'", *q);
- return -1;
- }
-
- if ((q[0] != '\0') && (q[1] != '\0')) {
- fr_strerror_printf("Trailing garbage in size string \"%s\"", str);
- return -1;
- }
-
- if (size > SIZE_MAX) {
- fr_strerror_printf("Value %" PRIu64 " is greater than the maximum "
- "file/memory size of this system (%zu)", size, (size_t)SIZE_MAX);
-
- goto overflow;
- }
-
- *out = (size_t)size;
-
- return 0;
-}
/** Multiply with modulo wrap
*
return true;
}
-/** Find the highest order bit in an unsigned 64 bit integer
+/** Find the highest order high bit in an unsigned 64 bit integer
*
* @return 0-64 indicating the position of the highest bit,
* with 0 indicating no high bits, 1 indicating the 1st
#endif
}
+/** Find the lowest order high bit in an unsigned 64 bit integer
+ *
+ * @return 0-64 indicating the position of the lowest bit,
+ * with 0 indicating no high bits, 1 indicating the 1st
+ * bit and 64 indicating the last bit.
+ */
+static inline uint8_t fr_low_bit_pos(uint64_t num)
+{
+ if (num == 0) return 0;
+
+#ifdef HAVE_BUILTIN_CLZLL
+ return __builtin_ctzll(num) + 1;
+#else
+ uint8_t ret = 1;
+
+ do {
+ if (num & 0x01) break;
+ ret++;
+ } while (num >>= 1);
+
+ return ret;
+#endif
+}
+
int fr_set_signal(int sig, sig_t func);
int fr_unset_signal(int sig);
int rad_lockfd(int fd, int lock_len);
uint64_t fr_multiply_mod(uint64_t lhs, uint64_t rhs, uint64_t mod);
-int fr_size_from_str(size_t *out, char const *str);
int8_t fr_pointer_cmp(void const *a, void const *b);
void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp);
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length) CC_HINT(nonnull);
--- /dev/null
+/*
+ * This program is 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Size printing and parsing functions
+ *
+ * @file src/lib/util/size.c
+ *
+ * @copyright 2022 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/sbuff.h>
+
+#include "size.h"
+
+/** Parse a size string with optional unit
+ *
+ * Default scale with no suffix is bytes.
+ *
+ * @param[out] out Parsed and scaled size
+ * @param[in] in sbuff to parse.
+ * @return
+ * - >0 on success.
+ * - <0 on error.
+ */
+fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in)
+{
+ fr_sbuff_t our_in = FR_SBUFF(in);
+ char c = '\0';
+ uint64_t size;
+
+ *out = 0;
+
+ if (fr_sbuff_out(NULL, &size, &our_in) < 0) return fr_sbuff_error(&our_in);
+ c = tolower(*fr_sbuff_current(&our_in));
+ switch (c) {
+ case 'n': /* nibble */
+ if (size & 0x01) {
+ fr_strerror_const("Sizes specified in nibbles must be an even number");
+ fr_sbuff_set_to_start(&our_in);
+ return fr_sbuff_error(&our_in);
+ }
+ size /= 2;
+ break;
+
+ case '\0':
+ case 'b': /* byte */
+ break;
+
+ case 'k': /* kibibyte */
+ if (!fr_multiply(&size, size, 1024)) {
+ overflow:
+ fr_strerror_printf("Value must be less than %zu", (size_t)SIZE_MAX);
+ fr_sbuff_set_to_start(&our_in);
+ return fr_sbuff_error(&our_in);
+ }
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ case 'm': /* mebibyte */
+ if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024))) goto overflow;
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ case 'g': /* gibibyte */
+ if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024 * 1024))) goto overflow;
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ case 't': /* tebibyte */
+ if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024 * 1024 * 1024))) goto overflow;
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ case 'p': /* pebibyte */
+ if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024 * 1024 * 1024 * 1024))) goto overflow;
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ case 'e': /* ebibyte */
+ if (!fr_multiply(&size, size, ((uint64_t)1024 * 1024 * 1024 * 1024 * 1024 * 1024))) goto overflow;
+ (void)fr_sbuff_next_if_char(&our_in, 'b');
+ break;
+
+ default:
+ fr_strerror_printf("Unknown unit '%c'", c);
+ return fr_sbuff_error(&our_in);
+ }
+
+ if (size > SIZE_MAX) {
+ fr_strerror_printf("Value %" PRIu64 " is greater than the maximum "
+ "file/memory size of this system (%zu)", size, (size_t)SIZE_MAX);
+
+ goto overflow;
+ }
+
+ *out = (size_t)size;
+
+ return fr_sbuff_set(in, &our_in);
+}
+
+/** Print a size string with unit
+ *
+ * Suffix is the largest unit possible without losing precision.
+ *
+ * @param[out] out To write size to.
+ * @param[in] in size to print.
+ * @return
+ * - >0 on success.
+ * - <0 on error.
+ */
+fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in)
+{
+ fr_sbuff_t our_out = FR_SBUFF(out);
+ uint8_t pos = fr_low_bit_pos((uint64_t)in);
+
+ /*
+ * Precision is greater than a kb (byte)
+ */
+ if (pos <= 10) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zub", in);
+ /*
+ * Precision is greater than a mb (kibibyte)
+ */
+ } else if (pos <= 20) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zuk", in / 1024);
+ /*
+ * Precision is greater than a gb (mebibyte)
+ */
+ } else if (pos <= 30) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zum", in / ((uint64_t)1024 * 1024));
+ /*
+ * Precision is greater than a tb (gibibyte)
+ */
+ } else if (pos <= 40) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zug", in / ((uint64_t)1024 * 1024 * 1024));
+ /*
+ * Precision is greater than a pb (tebibyte)
+ */
+ } else if (pos <= 50) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zut", in / ((uint64_t)1024 * 1024 * 1024 * 1024));
+ /*
+ * Precision is greater than a eb (pebibyte)
+ */
+ } else if (pos <= 60) {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zup", in / ((uint64_t)1024 * 1024 * 1024 * 1024 * 1024));
+
+ /*
+ * Precision is greater than a zb (exibyte)
+ */
+ } else {
+ FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zue", in / ((uint64_t)1024 * 1024 * 1024 * 1024 * 1024 * 1024));
+ }
+
+ return fr_sbuff_set(out, &our_out);
+}
--- /dev/null
+#pragma once
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Boxed value structures and functions to manipulate them
+ *
+ * @file src/lib/util/size.h
+ *
+ * @copyright 2022 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSIDH(size_h, "$Id$")
+
+
+fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in);
+
+fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in);
#include <freeradius-devel/util/atexit.h>
#include <freeradius-devel/util/base16.h>
#include <freeradius-devel/util/dcursor.h>
+#include <freeradius-devel/util/size.h>
#include <freeradius-devel/util/time.h>
#include <math.h>
case FR_TYPE_FLOAT64:
return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, tainted);
+ case FR_TYPE_SIZE:
+ if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
+ goto finish;
+
case FR_TYPE_BOOL:
fr_value_box_init(dst, dst_type, dst_enumv, tainted);
buffer[fr_sbuff_remaining(in)] = '\0';
switch (dst_type) {
- case FR_TYPE_SIZE:
- if (fr_size_from_str(&dst->datum.size, buffer) < 0) return -1;
- break;
-
case FR_TYPE_DATE:
{
if (dst_enumv) {