summaryrefslogtreecommitdiffstats
path: root/lib/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils.c')
-rw-r--r--lib/utils.c444
1 files changed, 308 insertions, 136 deletions
diff --git a/lib/utils.c b/lib/utils.c
index b5b457a..e1fdae1 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -6,10 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
+ * @ingroup core
* @defgroup utils Utilities
* @{
*/
@@ -25,7 +26,7 @@
int nl_debug = 0;
struct nl_dump_params nl_debug_dp = {
- .dp_type = NL_DUMP_FULL,
+ .dp_type = NL_DUMP_DETAILS,
};
static void __init nl_debug_init(void)
@@ -41,48 +42,6 @@ static void __init nl_debug_init(void)
nl_debug_dp.dp_fd = stderr;
}
-/**
- * @name Error Code Helpers
- * @{
- */
-
-static char *errbuf;
-static int nlerrno;
-
-/** @cond SKIP */
-int __nl_error(int err, const char *file, unsigned int line, const char *func,
- const char *fmt, ...)
-{
- char *user_err;
- va_list args;
-
- if (errbuf) {
- free(errbuf);
- errbuf = NULL;
- }
-
- nlerrno = err;
-
- if (fmt) {
- va_start(args, fmt);
- vasprintf(&user_err, fmt, args);
- va_end(args);
- }
-
-#ifdef VERBOSE_ERRORS
- asprintf(&errbuf, "%s:%u:%s: %s (errno = %s)",
- file, line, func, fmt ? user_err : "", strerror(err));
-#else
- asprintf(&errbuf, "%s (errno = %s)",
- fmt ? user_err : "", strerror(err));
-#endif
-
- if (fmt)
- free(user_err);
-
- return -err;
-}
-
int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
{
FILE *fd;
@@ -90,8 +49,7 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
fd = fopen(path, "r");
if (fd == NULL)
- return nl_error(errno, "Unable to open file %s for reading",
- path);
+ return -nl_syserr2nlerr(errno);
while (fgets(buf, sizeof(buf), fd)) {
int goodlen, err;
@@ -103,17 +61,17 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
num = strtol(buf, &end, 0);
if (end == buf)
- return nl_error(EINVAL, "Parsing error");
+ return -NLE_INVAL;
if (num == LONG_MIN || num == LONG_MAX)
- return nl_error(errno, "Number of out range");
+ return -NLE_RANGE;
while (*end == ' ' || *end == '\t')
end++;
goodlen = strcspn(end, "#\r\n\t ");
if (goodlen == 0)
- return nl_error(EINVAL, "Empty string");
+ return -NLE_INVAL;
end[goodlen] = '\0';
@@ -127,49 +85,6 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
return 0;
}
-/** @endcond */
-
-int nl_get_errno(void)
-{
- return nlerrno;
-}
-
-
-/**
- * Return error message for an error code
- * @return error message
- */
-char *nl_geterror(void)
-{
- if (errbuf)
- return errbuf;
-
- if (nlerrno)
- return strerror(nlerrno);
-
- return "Sucess\n";
-}
-
-/**
- * Print a libnl error message
- * @arg s error message prefix
- *
- * Prints the error message of the call that failed last.
- *
- * If s is not NULL and *s is not a null byte the argument
- * string is printed, followed by a colon and a blank. Then
- * the error message and a new-line.
- */
-void nl_perror(const char *s)
-{
- if (s && *s)
- fprintf(stderr, "%s: %s\n", s, nl_geterror());
- else
- fprintf(stderr, "%s\n", nl_geterror());
-}
-
-/** @} */
-
/**
* @name Unit Pretty-Printing
* @{
@@ -285,7 +200,7 @@ long nl_size2int(const char *str)
char *p;
long l = strtol(str, &p, 0);
if (p == str)
- return -1;
+ return -NLE_INVAL;
if (*p) {
if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
@@ -303,7 +218,7 @@ long nl_size2int(const char *str)
else if (!strcasecmp(p, "bit"))
l /= 8;
else if (strcasecmp(p, "b") != 0)
- return -1;
+ return -NLE_INVAL;
}
return l;
@@ -328,16 +243,16 @@ long nl_prob2int(const char *str)
double d = strtod(str, &p);
if (p == str)
- return -1;
+ return -NLE_INVAL;
if (d > 1.0)
d /= 100.0f;
if (d > 1.0f || d < 0.0f)
- return -1;
+ return -NLE_RANGE;
if (*p && strcmp(p, "%") != 0)
- return -1;
+ return -NLE_INVAL;
return rint(d * NL_PROB_MAX);
}
@@ -370,7 +285,7 @@ static void __init get_psched_settings(void)
{
char name[FILENAME_MAX];
FILE *fd;
- int got_hz = 0, got_tick = 0;
+ int got_hz = 0;
if (getenv("HZ")) {
long hz = strtol(getenv("HZ"), NULL, 0);
@@ -386,28 +301,25 @@ static void __init get_psched_settings(void)
if (getenv("TICKS_PER_USEC")) {
double t = strtod(getenv("TICKS_PER_USEC"), NULL);
-
ticks_per_usec = t;
- got_tick = 1;
}
+ else {
+ if (getenv("PROC_NET_PSCHED"))
+ snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
+ else if (getenv("PROC_ROOT"))
+ snprintf(name, sizeof(name), "%s/net/psched",
+ getenv("PROC_ROOT"));
+ else
+ strncpy(name, "/proc/net/psched", sizeof(name) - 1);
-
- if (getenv("PROC_NET_PSCHED"))
- snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
- else if (getenv("PROC_ROOT"))
- snprintf(name, sizeof(name), "%s/net/psched",
- getenv("PROC_ROOT"));
- else
- strncpy(name, "/proc/net/psched", sizeof(name) - 1);
-
- if ((fd = fopen(name, "r"))) {
- uint32_t tick, us, nom;
- int r = fscanf(fd, "%08x%08x%08x%*08x", &tick, &us, &nom);
-
- if (4 == r && nom == 1000000 && !got_tick)
+ if ((fd = fopen(name, "r"))) {
+ uint32_t tick, us;
+ /* the file contains 4 hexadecimals, but we just use
+ the first two of them */
+ fscanf(fd, "%08x %08x", &tick, &us);
ticks_per_usec = (double)tick/(double)us;
-
- fclose(fd);
+ fclose(fd);
+ }
}
}
@@ -442,25 +354,40 @@ uint32_t nl_ticks2us(uint32_t ticks)
return ticks / ticks_per_usec;
}
-long nl_time2int(const char *str)
+int nl_str2msec(const char *str, uint64_t *result)
{
+ uint64_t total = 0, l;
+ int plen;
char *p;
- long l = strtol(str, &p, 0);
- if (p == str)
- return -1;
- if (*p) {
- if (!strcasecmp(p, "min") == 0 || !strcasecmp(p, "m"))
- l *= 60;
- else if (!strcasecmp(p, "hour") || !strcasecmp(p, "h"))
- l *= 60*60;
- else if (!strcasecmp(p, "day") || !strcasecmp(p, "d"))
- l *= 60*60*24;
- else if (strcasecmp(p, "s") != 0)
- return -1;
- }
+ do {
+ l = strtoul(str, &p, 0);
+ if (p == str)
+ return -NLE_INVAL;
+ else if (*p) {
+ plen = strcspn(p, " \t");
+
+ if (!plen)
+ total += l;
+ else if (!strncasecmp(p, "sec", plen))
+ total += (l * 1000);
+ else if (!strncasecmp(p, "min", plen))
+ total += (l * 1000*60);
+ else if (!strncasecmp(p, "hour", plen))
+ total += (l * 1000*60*60);
+ else if (!strncasecmp(p, "day", plen))
+ total += (l * 1000*60*60*24);
+ else
+ return -NLE_INVAL;
+
+ str = p + plen;
+ } else
+ total += l;
+ } while (*str && *p);
+
+ *result = total;
- return l;
+ return 0;
}
/**
@@ -505,6 +432,47 @@ char * nl_msec2str(uint64_t msec, char *buf, size_t len)
/** @} */
/**
+ * @name Netlink Family Translations
+ * @{
+ */
+
+static struct trans_tbl nlfamilies[] = {
+ __ADD(NETLINK_ROUTE,route)
+ __ADD(NETLINK_USERSOCK,usersock)
+ __ADD(NETLINK_FIREWALL,firewall)
+ __ADD(NETLINK_INET_DIAG,inetdiag)
+ __ADD(NETLINK_NFLOG,nflog)
+ __ADD(NETLINK_XFRM,xfrm)
+ __ADD(NETLINK_SELINUX,selinux)
+ __ADD(NETLINK_ISCSI,iscsi)
+ __ADD(NETLINK_AUDIT,audit)
+ __ADD(NETLINK_FIB_LOOKUP,fib_lookup)
+ __ADD(NETLINK_CONNECTOR,connector)
+ __ADD(NETLINK_NETFILTER,netfilter)
+ __ADD(NETLINK_IP6_FW,ip6_fw)
+ __ADD(NETLINK_DNRTMSG,dnrtmsg)
+ __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
+ __ADD(NETLINK_GENERIC,generic)
+ __ADD(NETLINK_SCSITRANSPORT,scsitransport)
+ __ADD(NETLINK_ECRYPTFS,ecryptfs)
+};
+
+char * nl_nlfamily2str(int family, char *buf, size_t size)
+{
+ return __type2str(family, buf, size, nlfamilies,
+ ARRAY_SIZE(nlfamilies));
+}
+
+int nl_str2nlfamily(const char *name)
+{
+ return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
+}
+
+/**
+ * @}
+ */
+
+/**
* @name Link Layer Protocol Translations
* @{
*/
@@ -699,7 +667,7 @@ int nl_str2ip_proto(const char *name)
l = strtoul(name, &end, 0);
if (l == ULONG_MAX || *end != '\0')
- return -1;
+ return -NLE_OBJ_NOTFOUND;
return (int) l;
}
@@ -714,7 +682,6 @@ int nl_str2ip_proto(const char *name)
/**
* Handle a new line while dumping
* @arg params Dumping parameters
- * @arg line Number of lines dumped already.
*
* This function must be called before dumping any onto a
* new line. It will ensure proper prefixing as specified
@@ -722,8 +689,10 @@ int nl_str2ip_proto(const char *name)
*
* @note This function will NOT dump any newlines itself
*/
-void nl_new_line(struct nl_dump_params *params, int line)
+void nl_new_line(struct nl_dump_params *params)
{
+ params->dp_line++;
+
if (params->dp_prefix) {
int i;
for (i = 0; i < params->dp_prefix; i++) {
@@ -737,9 +706,27 @@ void nl_new_line(struct nl_dump_params *params, int line)
}
if (params->dp_nl_cb)
- params->dp_nl_cb(params, line);
+ params->dp_nl_cb(params, params->dp_line);
}
+static void dump_one(struct nl_dump_params *parms, const char *fmt,
+ va_list args)
+{
+ if (parms->dp_fd)
+ vfprintf(parms->dp_fd, fmt, args);
+ else if (parms->dp_buf || parms->dp_cb) {
+ char *buf = NULL;
+ vasprintf(&buf, fmt, args);
+ if (parms->dp_cb)
+ parms->dp_cb(parms, buf);
+ else
+ strncat(parms->dp_buf, buf,
+ parms->dp_buflen - strlen(parms->dp_buf) - 1);
+ free(buf);
+ }
+}
+
+
/**
* Dump a formatted character string
* @arg params Dumping parameters
@@ -754,10 +741,195 @@ void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
va_list args;
va_start(args, fmt);
- __dp_dump(params, fmt, args);
+ dump_one(params, fmt, args);
va_end(args);
}
+void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
+{
+ va_list args;
+
+ nl_new_line(parms);
+
+ va_start(args, fmt);
+ dump_one(parms, fmt, args);
+ va_end(args);
+}
+
+
/** @} */
+/** @cond SKIP */
+
+int __trans_list_add(int i, const char *a, struct nl_list_head *head)
+{
+ struct trans_list *tl;
+
+ tl = calloc(1, sizeof(*tl));
+ if (!tl)
+ return -NLE_NOMEM;
+
+ tl->i = i;
+ tl->a = strdup(a);
+
+ nl_list_add_tail(&tl->list, head);
+
+ return 0;
+}
+
+void __trans_list_clear(struct nl_list_head *head)
+{
+ struct trans_list *tl, *next;
+
+ nl_list_for_each_entry_safe(tl, next, head, list) {
+ free(tl->a);
+ free(tl);
+ }
+}
+
+char *__type2str(int type, char *buf, size_t len, struct trans_tbl *tbl,
+ size_t tbl_len)
+{
+ int i;
+ for (i = 0; i < tbl_len; i++) {
+ if (tbl[i].i == type) {
+ snprintf(buf, len, "%s", tbl[i].a);
+ return buf;
+ }
+ }
+
+ snprintf(buf, len, "0x%x", type);
+ return buf;
+}
+
+char *__list_type2str(int type, char *buf, size_t len,
+ struct nl_list_head *head)
+{
+ struct trans_list *tl;
+
+ nl_list_for_each_entry(tl, head, list) {
+ if (tl->i == type) {
+ snprintf(buf, len, "%s", tl->a);
+ return buf;
+ }
+ }
+
+ snprintf(buf, len, "0x%x", type);
+ return buf;
+}
+
+char *__flags2str(int flags, char *buf, size_t len,
+ struct trans_tbl *tbl, size_t tbl_len)
+{
+ int i;
+ int tmp = flags;
+
+ memset(buf, 0, len);
+
+ for (i = 0; i < tbl_len; i++) {
+ if (tbl[i].i & tmp) {
+ tmp &= ~tbl[i].i;
+ strncat(buf, tbl[i].a, len - strlen(buf) - 1);
+ if ((tmp & flags))
+ strncat(buf, ",", len - strlen(buf) - 1);
+ }
+ }
+
+ return buf;
+}
+
+int __str2type(const char *buf, struct trans_tbl *tbl, size_t tbl_len)
+{
+ unsigned long l;
+ char *end;
+ int i;
+
+ if (*buf == '\0')
+ return -NLE_INVAL;
+
+ for (i = 0; i < tbl_len; i++)
+ if (!strcasecmp(tbl[i].a, buf))
+ return tbl[i].i;
+
+ l = strtoul(buf, &end, 0);
+ if (l == ULONG_MAX || *end != '\0')
+ return -NLE_OBJ_NOTFOUND;
+
+ return (int) l;
+}
+
+int __list_str2type(const char *buf, struct nl_list_head *head)
+{
+ struct trans_list *tl;
+ unsigned long l;
+ char *end;
+
+ if (*buf == '\0')
+ return -NLE_INVAL;
+
+ nl_list_for_each_entry(tl, head, list) {
+ if (!strcasecmp(tl->a, buf))
+ return tl->i;
+ }
+
+ l = strtoul(buf, &end, 0);
+ if (l == ULONG_MAX || *end != '\0')
+ return -NLE_OBJ_NOTFOUND;
+
+ return (int) l;
+}
+
+int __str2flags(const char *buf, struct trans_tbl *tbl, size_t tbl_len)
+{
+ int i, flags = 0, len;
+ char *p = (char *) buf, *t;
+
+ for (;;) {
+ if (*p == ' ')
+ p++;
+
+ t = strchr(p, ',');
+ len = t ? t - p : strlen(p);
+ for (i = 0; i < tbl_len; i++)
+ if (!strncasecmp(tbl[i].a, p, len))
+ flags |= tbl[i].i;
+
+ if (!t)
+ return flags;
+
+ p = ++t;
+ }
+
+ return 0;
+}
+
+void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
+{
+ int type = params->dp_type;
+
+ if (type < 0 || type > NL_DUMP_MAX)
+ BUG();
+
+ params->dp_line = 0;
+
+ if (params->dp_dump_msgtype) {
+#if 0
+ /* XXX */
+ char buf[64];
+
+ dp_dump_line(params, 0, "%s ",
+ nl_cache_mngt_type2name(obj->ce_ops,
+ obj->ce_ops->co_protocol,
+ obj->ce_msgtype,
+ buf, sizeof(buf)));
+#endif
+ params->dp_pre_dump = 1;
+ }
+
+ if (obj->ce_ops->oo_dump[type])
+ obj->ce_ops->oo_dump[type](obj, params);
+}
+
+/** @endcond */
+
/** @} */