@@ -29,7 +29,7 @@ esac
regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT"
regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
-Wmissing-prototypes -Wshadow -Wstrict-prototypes \
- -Wformat=2 -pipe"
+ -Wformat=2 -Wno-format-nonliteral -pipe"
AC_SUBST([regular_CPPFLAGS])
AC_SUBST([regular_CFLAGS])
AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libnetfilter_acct/Makefile include/linux/Makefile include/linux/netfilter/Makefile examples/Makefile libnetfilter_acct.pc doxygen.cfg])
@@ -16,9 +16,62 @@ enum nfacct_attr_type {
NFACCT_ATTR_BYTES,
};
+struct nfacct_options;
+
+enum nfacct_option_type {
+ NFACCT_OPT_FMT = 0, /* number format option */
+ NFACCT_OPT_PCW, /* packets count column width */
+ NFACCT_OPT_BCW, /* bytes count column width */
+};
+
+enum nfacct_format {
+ NFACCT_FMT_DEFAULT=0,
+ NFACCT_FMT_NONE,
+ NFACCT_FMT_TRIPLETS,
+ NFACCT_FMT_IEC,
+ NFACCT_FMT_IEC_KIBIBYTE,
+ NFACCT_FMT_IEC_MEBIBYTE,
+ NFACCT_FMT_IEC_GIBIBYTE,
+ NFACCT_FMT_IEC_TEBIBYTE,
+ NFACCT_FMT_IEC_PEBIBYTE,
+ NFACCT_FMT_IEC_EXBIBYTE,
+ NFACCT_FMT_SI,
+ NFACCT_FMT_SI_KILOBYTE,
+ NFACCT_FMT_SI_MEGABYTE,
+ NFACCT_FMT_SI_GIGABYTE,
+ NFACCT_FMT_SI_TERABYTE,
+ NFACCT_FMT_SI_PETABYTE,
+ NFACCT_FMT_SI_EXABYTE,
+ NFACCT_FMT_MAX,
+};
+
+static const char *nfacct_fmt_keys[NFACCT_FMT_MAX + 1] = {
+ [NFACCT_FMT_DEFAULT] = "def",
+ [NFACCT_FMT_NONE] = "raw",
+ [NFACCT_FMT_TRIPLETS] = "3pl",
+ [NFACCT_FMT_IEC] = "iec",
+ [NFACCT_FMT_IEC_KIBIBYTE] = "kib",
+ [NFACCT_FMT_IEC_MEBIBYTE] = "mib",
+ [NFACCT_FMT_IEC_GIBIBYTE] = "gib",
+ [NFACCT_FMT_IEC_TEBIBYTE] = "tib",
+ [NFACCT_FMT_IEC_PEBIBYTE] = "pib",
+ [NFACCT_FMT_IEC_EXBIBYTE] = "eib",
+ [NFACCT_FMT_SI] = "si",
+ [NFACCT_FMT_SI_KILOBYTE] = "kb",
+ [NFACCT_FMT_SI_MEGABYTE] = "mb",
+ [NFACCT_FMT_SI_GIGABYTE] = "gb",
+ [NFACCT_FMT_SI_TERABYTE] = "tb",
+ [NFACCT_FMT_SI_PETABYTE] = "pb",
+ [NFACCT_FMT_SI_EXABYTE] = "eb",
+ [NFACCT_FMT_MAX] = "",
+};
+
struct nfacct *nfacct_alloc(void);
void nfacct_free(struct nfacct *nfacct);
+struct nfacct_options *nfacct_options_alloc(void);
+void nfacct_options_free(struct nfacct_options *options);
+
void nfacct_attr_set(struct nfacct *nfacct, enum nfacct_attr_type type, const void *data);
void nfacct_attr_set_str(struct nfacct *nfacct, enum nfacct_attr_type type, const char *name);
void nfacct_attr_set_u64(struct nfacct *nfacct, enum nfacct_attr_type type, uint64_t value);
@@ -28,6 +81,22 @@ const void *nfacct_attr_get(struct nfacct *nfacct, enum nfacct_attr_type type);
const char *nfacct_attr_get_str(struct nfacct *nfacct, enum nfacct_attr_type type);
uint64_t nfacct_attr_get_u64(struct nfacct *nfacct, enum nfacct_attr_type type);
+void nfacct_option_set(struct nfacct_options *options,
+ enum nfacct_option_type type, const void *data);
+void nfacct_option_set_u16(struct nfacct_options *options,
+ enum nfacct_option_type type, uint16_t value);
+void nfacct_option_set_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type, size_t value);
+void nfacct_option_unset(struct nfacct_options *options,
+ enum nfacct_option_type type);
+
+const void *nfacct_option_get(struct nfacct_options *options,
+ enum nfacct_option_type type);
+uint16_t nfacct_option_get_u16(struct nfacct_options *options,
+ enum nfacct_option_type type);
+size_t nfacct_option_get_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type);
+
void parse_nfacct_name(char *buf, const char *name);
struct nlmsghdr;
@@ -45,10 +114,16 @@ int nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct
/* print only the bytes and name columns */
#define NFACCT_SNPRINTF_F_BONLY (1 << 3)
+/* print numbers only (formatted), useful for determining max column width */
+#define NFACCT_SNPRINTF_F_NUMONLY (1 << 4)
+
#define NFACCT_SNPRINTF_T_PLAIN 0
#define NFACCT_SNPRINTF_T_XML 1
int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct, uint16_t type, uint16_t flags);
+int nfacct_snprintf_with_options(char *buf, size_t size, struct nfacct *nfacct,
+ uint16_t type, uint16_t flags,
+ struct nfacct_options *options);
#ifdef __cplusplus
} /* extern "C" */
@@ -13,6 +13,7 @@
#include <endian.h>
#include <stdlib.h>
#include <string.h>
+#include <locale.h>
#include <inttypes.h>
#include <libmnl/libmnl.h>
@@ -63,6 +64,13 @@ struct nfacct {
uint32_t bitset;
};
+struct nfacct_options {
+ uint16_t fmt;
+ size_t pcw;
+ size_t bcw;
+ uint32_t bitset;
+};
+
/**
* \defgroup nfacct Accounting object handling
* @{
@@ -91,6 +99,28 @@ void nfacct_free(struct nfacct *nfacct)
EXPORT_SYMBOL(nfacct_free);
/**
+ * nfacct_options_alloc - allocate a new accounting options object
+ *
+ * In case of success, this function returns a valid pointer, otherwise NULL
+ * s returned and errno is appropriately set.
+ */
+struct nfacct_options *nfacct_options_alloc(void)
+{
+ return calloc(1, sizeof(struct nfacct_options));
+}
+EXPORT_SYMBOL(nfacct_options_alloc);
+
+/**
+ * nfacct_options_free - release one accounting options object
+ * \param nfacct pointer to the accounting options object
+ */
+void nfacct_options_free(struct nfacct_options *options)
+{
+ free(options);
+}
+EXPORT_SYMBOL(nfacct_options_free);
+
+/**
* nfacct_attr_set - set one attribute of the accounting object
* \param nfacct pointer to the accounting object
* \param type attribute type you want to set
@@ -228,18 +258,294 @@ uint64_t nfacct_attr_get_u64(struct nfacct *nfacct, enum nfacct_attr_type type)
}
EXPORT_SYMBOL(nfacct_attr_get_u64);
+/**
+ * nfacct_option_set - set one option of the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param data pointer to data that will be used to set this option
+ */
+void
+nfacct_option_set(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ const void *data)
+{
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ options->fmt = *((uint16_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_FMT);
+ break;
+ case NFACCT_OPT_PCW:
+ options->pcw = *((size_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_PCW);
+ break;
+ case NFACCT_OPT_BCW:
+ options->bcw = *((size_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_BCW);
+ break;
+ }
+}
+EXPORT_SYMBOL(nfacct_option_set);
+
+/**
+ * nfacct_option_set_u16 - set one option in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param value unsigned 16-bit integer
+ */
+void
+nfacct_option_set_u16(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ uint16_t value)
+{
+ nfacct_option_set(options, type, &value);
+}
+EXPORT_SYMBOL(nfacct_option_set_u16);
+
+/**
+ * nfacct_attr_set_tsize - set one options in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param value size_t (arch-dependent) integer
+ */
+void
+nfacct_option_set_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ size_t value)
+{
+ nfacct_option_set(options, type, &value);
+}
+EXPORT_SYMBOL(nfacct_option_set_tsize);
+
+/**
+ * nfacct_option_unset - unset one option in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to unset
+ */
+void
+nfacct_option_unset(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ options->bitset &= ~(1 << NFACCT_OPT_FMT);
+ break;
+ case NFACCT_OPT_PCW:
+ options->bitset &= ~(1 << NFACCT_OPT_PCW);
+ break;
+ case NFACCT_OPT_BCW:
+ options->bitset &= ~(1 << NFACCT_OPT_BCW);
+ break;
+ }
+}
+EXPORT_SYMBOL(nfacct_option_unset);
+
+/**
+ * nfacct_option_get - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a valid pointer to the option data. If a
+ * unsupported option is used, this returns NULL.
+ */
+const void *nfacct_option_get(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = NULL;
+
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ if (options->bitset & (1 << NFACCT_OPT_FMT))
+ ret = &options->fmt;
+ break;
+ case NFACCT_OPT_PCW:
+ if (options->bitset & (1 << NFACCT_OPT_PCW))
+ ret = &options->pcw;
+ break;
+ case NFACCT_OPT_BCW:
+ if (options->bitset & (1 << NFACCT_OPT_BCW))
+ ret = &options->bcw;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(nfacct_option_get);
+
+/**
+ * nfacct_option_get_u16 - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a unsigned 16-bits integer. If the option is
+ * unsupported, this returns NULL.
+ */
+uint16_t nfacct_option_get_u16(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = nfacct_option_get(options, type);
+ return ret ? *((uint16_t *)ret) : 0;
+}
+EXPORT_SYMBOL(nfacct_option_get_u16);
+
+/**
+ * nfacct_attr_get_tsize - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a size_t (arch-dependent) integer. If the option is
+ * unsupported, this returns NULL.
+ */
+size_t nfacct_option_get_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = nfacct_option_get(options, type);
+ return ret ? *((size_t *)ret) : 0;
+}
+EXPORT_SYMBOL(nfacct_option_get_tsize);
+
+#define KiB ((uint64_t) 1 << 10)
+#define MiB ((uint64_t) KiB << 10)
+#define GiB ((uint64_t) MiB << 10)
+#define TiB ((uint64_t) GiB << 10)
+#define PiB ((uint64_t) TiB << 10)
+#define EiB ((uint64_t) PiB << 10)
+#define KB ((uint64_t) 1*1000)
+#define MB ((uint64_t) KB*1000)
+#define GB ((uint64_t) MB*1000)
+#define TB ((uint64_t) GB*1000)
+#define PB ((uint64_t) TB*1000)
+#define EB ((uint64_t) PB*1000)
+
+#define NFACCT_STR_PLAIN_NUMONLY "%s %s"
#define NFACCT_STR_PLAIN_SAVE_BASE "name=%s pkts=%"PRIu64 \
" bytes=%"PRIu64
-#define NFACCT_STR_PLAIN "{ pkts = %.20"PRIu64", " \
- "bytes = %.20"PRIu64" } = %s"
-#define NFACCT_STR_PLAIN_BONLY "{ bytes = %.20"PRIu64 " } = %s"
+#define NFACCT_STR_PLAIN_NEW "[ pkts = %%%zus" \
+ " bytes = %%%zus ] = %%s"
+#define NFACCT_STR_PLAIN "{ pkts = %%%zus, " \
+ "bytes = %%%zus } = %%s;"
+#define NFACCT_STR_PLAIN_BONLY "[ bytes = %%%zus ] = %%s"
#define NFACCT_XML_NAME "<name>%s</name>"
-#define NFACCT_XML_PKTS "<pkts>%.20"PRIu64"</pkts>"
-#define NFACCT_XML_BYTES "<bytes>%.20"PRIu64"</bytes>"
+#define NFACCT_XML_PKTS "<pkts fmt=\"%s\">%s</pkts>"
+#define NFACCT_XML_BYTES "<bytes fmt=\"%s\">%s</bytes>"
#define NFACCT_STR_XML_BONLY "<obj>" NFACCT_XML_NAME \
NFACCT_XML_BYTES
+#define NFACCT_STR_XML_COMPAT "<obj><name>%s</name>" \
+ "<pkts>%s</pkts>" \
+ "<bytes>%s</bytes>"
#define NFACCT_STR_XML "<obj>" NFACCT_XML_NAME \
NFACCT_XML_PKTS NFACCT_XML_BYTES
+#define NFACCT_STR_DEFAULT "%020.0f%s"
+#define NFACCT_STR_NONE "%.0f%s"
+#define NFACCT_STR_TRIPLETS "%'.0f%s"
+#define NFACCT_STR_SI_IEC "%'.3f%s"
+
+#define NFACCT_NUM_DEFAULT { .value = 0., .str = "" }
+
+struct nfacct_number {
+ float value;
+ char str[30];
+};
+
+struct nfacct_num {
+ uint64_t num;
+ char name[4];
+};
+
+static struct nfacct_num nfacct_num_keys[] = {
+ [NFACCT_FMT_DEFAULT] = { .num = 1, .name = "" },
+ [NFACCT_FMT_NONE] = { .num = 1, .name = "" },
+ [NFACCT_FMT_TRIPLETS] = { .num = 1, .name = "" },
+ [NFACCT_FMT_IEC] = { .num = 1, .name = "" },
+ [NFACCT_FMT_IEC_KIBIBYTE] = { .num = KiB, .name = "KiB" },
+ [NFACCT_FMT_IEC_MEBIBYTE] = { .num = MiB, .name = "MiB" },
+ [NFACCT_FMT_IEC_GIBIBYTE] = { .num = GiB, .name = "GiB" },
+ [NFACCT_FMT_IEC_TEBIBYTE] = { .num = TiB, .name = "TiB" },
+ [NFACCT_FMT_IEC_PEBIBYTE] = { .num = PiB, .name = "PiB" },
+ [NFACCT_FMT_IEC_EXBIBYTE] = { .num = EiB, .name = "EiB" },
+ [NFACCT_FMT_SI] = { .num = 1, .name = "" },
+ [NFACCT_FMT_SI_KILOBYTE] = { .num = KB, .name = "KB" },
+ [NFACCT_FMT_SI_MEGABYTE] = { .num = MB, .name = "MB" },
+ [NFACCT_FMT_SI_GIGABYTE] = { .num = GB, .name = "GB" },
+ [NFACCT_FMT_SI_TERABYTE] = { .num = TB, .name = "TB" },
+ [NFACCT_FMT_SI_PETABYTE] = { .num = PB, .name = "PB" },
+ [NFACCT_FMT_SI_EXABYTE] = { .num = EB, .name = "EB" },
+};
+
+#define NFACCT_SET_RET(x) nf->value /= nfacct_num_keys[x].num; \
+ name = nfacct_num_keys[x].name;
+#define NFACCT_SET_STR_FMT(x) NFACCT_STR_##x
+#define NFACCT_GET_FMT(x) nfacct_fmt_keys[x]
+#define NFACCT_SET_RET_FMT(x) snprintf(nf->str,sizeof(nf->str), \
+ NFACCT_SET_STR_FMT(x),nf->value, name)
+
+static void
+format_number(struct nfacct_number *nf, const uint64_t val,
+ const enum nfacct_format fmt)
+{
+ nf->value = (float) val;
+ char *name = "";
+ switch (fmt) {
+ case NFACCT_FMT_IEC:
+ if (nf->value >= EiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_EXBIBYTE);
+ } else if (nf->value >= PiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_PEBIBYTE);
+ } else if (nf->value >= TiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_TEBIBYTE);
+ } else if (nf->value >= GiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_GIBIBYTE);
+ } else if (nf->value >= MiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_MEBIBYTE);
+ } else if (nf->value >= KiB) {
+ NFACCT_SET_RET(NFACCT_FMT_IEC_KIBIBYTE);
+ }
+ NFACCT_SET_RET_FMT(SI_IEC);
+ break;
+ case NFACCT_FMT_SI:
+ if (nf->value >= EB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_EXABYTE);
+ } else if (nf->value >= PB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_PETABYTE);
+ } else if (nf->value >= TB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_TERABYTE);
+ } else if (nf->value >= GB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_GIGABYTE);
+ } else if (nf->value >= MB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_MEGABYTE);
+ } else if (nf->value >= KB) {
+ NFACCT_SET_RET(NFACCT_FMT_SI_KILOBYTE);
+ }
+ NFACCT_SET_RET_FMT(SI_IEC);
+ break;
+ case NFACCT_FMT_IEC_EXBIBYTE:
+ case NFACCT_FMT_IEC_PEBIBYTE:
+ case NFACCT_FMT_IEC_TEBIBYTE:
+ case NFACCT_FMT_IEC_GIBIBYTE:
+ case NFACCT_FMT_IEC_MEBIBYTE:
+ case NFACCT_FMT_IEC_KIBIBYTE:
+ case NFACCT_FMT_SI_EXABYTE:
+ case NFACCT_FMT_SI_PETABYTE:
+ case NFACCT_FMT_SI_TERABYTE:
+ case NFACCT_FMT_SI_GIGABYTE:
+ case NFACCT_FMT_SI_MEGABYTE:
+ case NFACCT_FMT_SI_KILOBYTE:
+ NFACCT_SET_RET(fmt);
+ NFACCT_SET_RET_FMT(SI_IEC);
+ break;
+ case NFACCT_FMT_DEFAULT:
+ NFACCT_SET_RET(NFACCT_FMT_DEFAULT);
+ NFACCT_SET_RET_FMT(DEFAULT);
+ break;
+ case NFACCT_FMT_NONE:
+ NFACCT_SET_RET(NFACCT_FMT_NONE);
+ NFACCT_SET_RET_FMT(NONE);
+ break;
+ case NFACCT_FMT_TRIPLETS:
+ NFACCT_SET_RET(NFACCT_FMT_TRIPLETS);
+ NFACCT_SET_RET_FMT(TRIPLETS);
+ default:
+ break;
+ }
+}
void
parse_nfacct_name(char *buf, const char *name)
@@ -324,34 +630,130 @@ void parse_nfacct_name_xml(char *buf, const char *name)
}
}
+#define NFACCT_DEFAULT_LOCALE "en_GB"
+
+static void init_locale(void) {
+ char *lang;
+ char *env = "LANG";
+ lang = getenv(env);
+ setlocale(LC_ALL,(lang == NULL ? NFACCT_DEFAULT_LOCALE : lang));
+}
+
+/* fmt field bit definitions */
+#define _nfacct_offset_fmt 0
+#define _nfacct_offset_bytes _nfacct_offset_fmt
+#define _nfacct_offset_pkts 8
+#define _nfacct_bitsize_fmt 0xffff
+#define _nfacct_bitsize_bytes 0xff
+#define _nfacct_bitsize_pkts _nfacct_bitsize_bytes
+
+/* internal fmt help functions */
+#define _nfacct_get_mask(x) ((uint16_t)_nfacct_bitsize_##x \
+ << _nfacct_offset_##x)
+#define _nfacct_get_value(x,f) (((uint16_t)x & \
+ _nfacct_get_mask(f)) >> _nfacct_offset_##f)
+
+/* fmt help functions */
+#define nfacct_get_fmt(x) _nfacct_get_value(x,fmt)
+#define nfacct_get_bytes_fmt(x) _nfacct_get_value(x,bytes)
+#define nfacct_get_pkt_fmt(x) _nfacct_get_value(x,pkts)
+
static int
nfacct_snprintf_plain(char *buf, size_t rem, struct nfacct *nfacct,
- uint16_t flags)
+ uint16_t flags, struct nfacct_options *options)
{
- int ret;
+ int ret = 0;
+ bool compat = (options == NULL);
+ uint16_t fmt;
+ uint64_t pkts = 0, bytes = 0;
char nfacct_name[NFACCT_NAME_MAX * 2 + 4];
+ char fmt_str[sizeof(NFACCT_STR_PLAIN_NEW) +
+ sizeof(NFACCT_STR_DEFAULT) * 5 + 10];
+ struct nfacct_number pn = NFACCT_NUM_DEFAULT,
+ bn = NFACCT_NUM_DEFAULT;
- parse_nfacct_name(nfacct_name,
- nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME));
if (flags & NFACCT_SNPRINTF_F_FULL) {
/* default: print pkts + bytes + name */
- ret = snprintf(buf, rem, NFACCT_STR_PLAIN,
- nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS),
- nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES),
- nfacct_name);
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME));
+
+ if (compat) {
+ fmt = NFACCT_FMT_MAX;
+ snprintf(fmt_str, sizeof(fmt_str), NFACCT_STR_PLAIN,
+ (size_t)0, (size_t)0);
+ } else {
+ fmt = nfacct_option_get_u16(options, NFACCT_OPT_FMT);
+ snprintf(fmt_str, sizeof(fmt_str),
+ NFACCT_STR_PLAIN_NEW,
+ nfacct_option_get_tsize(options,
+ NFACCT_OPT_PCW),
+ nfacct_option_get_tsize(options,
+ NFACCT_OPT_BCW));
+ }
+
+ if (fmt == NFACCT_FMT_MAX)
+ fmt = NFACCT_FMT_DEFAULT;
+
+ if (nfacct_get_fmt(fmt) > NFACCT_FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, nfacct_get_pkt_fmt(fmt));
+ format_number(&bn, bytes, nfacct_get_bytes_fmt(fmt));
+
+ ret = snprintf(buf, rem, fmt_str, pn.str, bn.str,
+ nfacct_name);
} else if (flags & NFACCT_SNPRINTF_F_SAVE) {
/* save: format useful for 'restore' */
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME));
ret = snprintf(buf, rem, NFACCT_STR_PLAIN_SAVE_BASE,
nfacct_name,
nfacct_attr_get_u64(nfacct,NFACCT_ATTR_PKTS),
nfacct_attr_get_u64(nfacct,NFACCT_ATTR_BYTES));
} else if (flags & NFACCT_SNPRINTF_F_BONLY) {
/* print bytes + name only */
- ret = snprintf(buf, rem, NFACCT_STR_PLAIN_BONLY,
- nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES),
- nfacct_name);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME));
+ fmt = nfacct_option_get_u16(options, NFACCT_OPT_FMT);
+
+ if (fmt == NFACCT_FMT_MAX)
+ fmt = NFACCT_FMT_DEFAULT;
+
+ if (nfacct_get_fmt(fmt) > NFACCT_FMT_NONE)
+ init_locale();
+
+ format_number(&bn, bytes, nfacct_get_bytes_fmt(fmt));
+ snprintf(fmt_str, sizeof(fmt_str), NFACCT_STR_PLAIN_BONLY,
+ nfacct_option_get_tsize(options,NFACCT_OPT_BCW));
+ ret = snprintf(buf, rem, fmt_str, bn.str, nfacct_name);
+ } else if (flags & NFACCT_SNPRINTF_F_NUMONLY) {
+ /* numbers only: to determine the maximum column width */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ fmt = nfacct_option_get_u16(options, NFACCT_OPT_FMT);
+
+ if (fmt == NFACCT_FMT_MAX)
+ fmt = NFACCT_FMT_DEFAULT;
+
+ if (nfacct_get_fmt(fmt) > NFACCT_FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, nfacct_get_pkt_fmt(fmt));
+ format_number(&bn, bytes, nfacct_get_bytes_fmt(fmt));
+
+ ret = snprintf(buf, rem, NFACCT_STR_PLAIN_NUMONLY,
+ pn.str, bn.str);
} else {
/* print out name only */
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME));
ret = snprintf(buf, rem, "%s\n", nfacct_name);
}
@@ -398,28 +800,58 @@ nfacct_snprintf_xml_localtime(char *buf, unsigned int rem, const struct tm *tm)
static int
nfacct_snprintf_xml(char *buf, size_t rem, struct nfacct *nfacct,
- uint16_t flags)
+ uint16_t flags, struct nfacct_options *options)
{
int ret = 0;
+ bool compat = (options == NULL);
unsigned int size = 0, offset = 0;
+ uint16_t fmt;
+ uint64_t pkts = 0, bytes = 0;
char nfacct_name[NFACCT_NAME_MAX * 6 + 1];
+ struct nfacct_number pn = NFACCT_NUM_DEFAULT,
+ bn = NFACCT_NUM_DEFAULT;
parse_nfacct_name_xml(nfacct_name,
nfacct_attr_get_str(nfacct,
NFACCT_ATTR_NAME));
+ if (compat) {
+ fmt = NFACCT_FMT_MAX;
+ } else {
+ fmt = nfacct_option_get_u16(options, NFACCT_OPT_FMT);
+ }
if (flags & NFACCT_SNPRINTF_F_BONLY) {
/* print name + bytes only */
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+
+ if (fmt == NFACCT_FMT_MAX)
+ fmt = NFACCT_FMT_DEFAULT;
+
+ format_number(&bn, bytes, NFACCT_FMT_NONE);
ret = snprintf(buf, rem, NFACCT_STR_XML_BONLY, nfacct_name,
- nfacct_attr_get_u64(nfacct,
- NFACCT_ATTR_BYTES));
+ NFACCT_GET_FMT(nfacct_get_bytes_fmt(fmt)),
+ bn.str);
BUFFER_SIZE(ret, size, rem, offset);
} else {
/* default/everything else: print name + pkts + bytes */
- ret = snprintf(buf, rem, NFACCT_STR_XML, nfacct_name,
- nfacct_attr_get_u64(nfacct,
- NFACCT_ATTR_BYTES),
- nfacct_attr_get_u64(nfacct,
- NFACCT_ATTR_PKTS));
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+
+ if (fmt == NFACCT_FMT_MAX)
+ fmt = NFACCT_FMT_DEFAULT;
+
+ format_number(&pn, pkts, NFACCT_FMT_NONE);
+ format_number(&bn, bytes, NFACCT_FMT_NONE);
+
+ if (compat) {
+ ret = snprintf(buf, rem, NFACCT_STR_XML_COMPAT,
+ nfacct_name, pn.str, bn.str);
+ } else {
+ ret = snprintf(buf, rem, NFACCT_STR_XML, nfacct_name,
+ NFACCT_GET_FMT(nfacct_get_pkt_fmt(fmt)),
+ pn.str,
+ NFACCT_GET_FMT(nfacct_get_bytes_fmt(fmt)),
+ bn.str);
+ }
BUFFER_SIZE(ret, size, rem, offset);
}
@@ -443,27 +875,30 @@ err:
}
/**
- * nfacct_snprintf - print accounting object into one buffer
+ * nfacct_snprintf_with_options - print accounting object into one buffer
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
* \param nfacct: pointer to a valid accounting object.
* \param type: format output type, NFACCT_SNPRINTF_T_[PLAIN|XML]
* \param flags: output flags (NFACCT_SNPRINTF_F_FULL).
+ * \param options: nfacct options structure.
*
* This function returns -1 in case that some mandatory attributes are
* missing. On sucess, it returns 0.
*/
-int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
- uint16_t type, uint16_t flags)
+int nfacct_snprintf_with_options(char *buf, size_t size,
+ struct nfacct *nfacct,
+ uint16_t type, uint16_t flags,
+ struct nfacct_options *options)
{
int ret = 0;
switch(type) {
case NFACCT_SNPRINTF_T_PLAIN:
- ret = nfacct_snprintf_plain(buf, size, nfacct, flags);
+ ret = nfacct_snprintf_plain(buf,size,nfacct,flags,options);
break;
case NFACCT_SNPRINTF_T_XML:
- ret = nfacct_snprintf_xml(buf, size, nfacct, flags);
+ ret = nfacct_snprintf_xml(buf,size,nfacct,flags,options);
break;
default:
ret = -1;
@@ -471,6 +906,25 @@ int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
}
return ret;
}
+EXPORT_SYMBOL(nfacct_snprintf_with_options);
+
+/**
+ * nfacct_snprintf - print accounting object into one buffer
+ * \param buf: pointer to buffer that is used to print the object
+ * \param size: size of the buffer (or remaining room in it).
+ * \param nfacct: pointer to a valid accounting object.
+ * \param type: format output type, NFACCT_SNPRINTF_T_[PLAIN|XML]
+ * \param flags: output flags (NFACCT_SNPRINTF_F_FULL).
+ *
+ * This function returns -1 in case that some mandatory attributes are
+ * missing. On sucess, it returns 0.
+ */
+int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
+ uint16_t type, uint16_t flags)
+{
+ return nfacct_snprintf_with_options(buf, size, nfacct,
+ type, flags, NULL);
+}
EXPORT_SYMBOL(nfacct_snprintf);
/**
@@ -21,5 +21,15 @@ local: *;
LIBNETFILTER_ACCT_1.1 {
nfacct_snprintf;
+ nfacct_options_alloc;
+ nfacct_options_free;
+ nfacct_option_set;
+ nfacct_option_set_u16;
+ nfacct_option_set_tsize;
+ nfacct_option_unset;
+ nfacct_option_get;
+ nfacct_option_get_u16;
+ nfacct_option_get_tsize;
parse_nfacct_name;
+ nfacct_snprintf_with_options;
} LIBNETFILTER_ACCT_1.0;
* add a separate nfacct_options struct with its get/set functions, allowing userspace programs, like nfacct, to specify the width of the columns which are to be printed, so that they are no longer hard-coded into the printing template itself. This allows column width to be "adjusted", depending on the value of each property; * add a separate NFACCT_SNPRINTF_F_NUMONLY template, which prints the numbers-only properties of the accounting objects (formatted - see below) - useful to the nfnetlink callback function in order to determine the maximum column width, which needs to be used to print each column. * add a new nfacct_snprintf_with_options function enhancing the existing API to enable "options" to be specified during printing properties of nfacct objects. * allow on-the-fly formatting, using over 14 different formats when printing accounting objects. This formatting, if specified, applies to *all* accounting objects. Signed-off-by: Michael Zintakis <michael.zintakis@googlemail.com> --- configure.ac | 2 +- include/libnetfilter_acct/libnetfilter_acct.h | 75 ++++ src/libnetfilter_acct.c | 512 ++++++++++++++++++++++++-- src/libnetfilter_acct.map | 10 + 4 files changed, 569 insertions(+), 30 deletions(-)