422 lines
8.5 KiB
C
422 lines
8.5 KiB
C
/*
|
|
* utils.c General purpose utilities
|
|
*
|
|
* Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
|
|
* Copyright (c) 2013 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <bmon/bmon.h>
|
|
#include <bmon/conf.h>
|
|
#include <bmon/utils.h>
|
|
|
|
void *xcalloc(size_t n, size_t s)
|
|
{
|
|
void *d = calloc(n, s);
|
|
|
|
if (NULL == d) {
|
|
fprintf(stderr, "xalloc: Out of memory\n");
|
|
exit(ENOMEM);
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
void *xrealloc(void *p, size_t s)
|
|
{
|
|
void *d = realloc(p, s);
|
|
|
|
if (NULL == d) {
|
|
fprintf(stderr, "xrealloc: Out of memory!\n");
|
|
exit(ENOMEM);
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
void xfree(void *d)
|
|
{
|
|
if (d)
|
|
free(d);
|
|
}
|
|
|
|
float timestamp_to_float(timestamp_t *src)
|
|
{
|
|
return (float) src->tv_sec + ((float) src->tv_usec / 1000000.0f);
|
|
}
|
|
|
|
int64_t timestamp_to_int(timestamp_t *src)
|
|
{
|
|
return (src->tv_sec * 1000000ULL) + src->tv_usec;
|
|
}
|
|
|
|
void float_to_timestamp(timestamp_t *dst, float src)
|
|
{
|
|
dst->tv_sec = (time_t) src;
|
|
dst->tv_usec = (src - ((float) ((time_t) src))) * 1000000.0f;
|
|
}
|
|
|
|
void timestamp_add(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
|
|
{
|
|
dst->tv_sec = src1->tv_sec + src2->tv_sec;
|
|
dst->tv_usec = src1->tv_usec + src2->tv_usec;
|
|
|
|
if (dst->tv_usec >= 1000000) {
|
|
dst->tv_sec++;
|
|
dst->tv_usec -= 1000000;
|
|
}
|
|
}
|
|
|
|
void timestamp_sub(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
|
|
{
|
|
dst->tv_sec = src1->tv_sec - src2->tv_sec;
|
|
dst->tv_usec = src1->tv_usec - src2->tv_usec;
|
|
if (dst->tv_usec < 0) {
|
|
dst->tv_sec--;
|
|
dst->tv_usec += 1000000;
|
|
}
|
|
}
|
|
|
|
int timestamp_le(timestamp_t *a, timestamp_t *b)
|
|
{
|
|
if (a->tv_sec > b->tv_sec)
|
|
return 0;
|
|
|
|
if (a->tv_sec < b->tv_sec || a->tv_usec <= b->tv_usec)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int timestamp_is_negative(timestamp_t *ts)
|
|
{
|
|
return (ts->tv_sec < 0 || ts->tv_usec < 0);
|
|
}
|
|
|
|
void update_timestamp(timestamp_t *dst)
|
|
{
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
dst->tv_sec = tv.tv_sec;
|
|
dst->tv_usec = tv.tv_usec;
|
|
}
|
|
|
|
void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2)
|
|
{
|
|
ts1->tv_sec = ts2->tv_sec;
|
|
ts2->tv_usec = ts2->tv_usec;
|
|
}
|
|
|
|
float timestamp_diff(timestamp_t *t1, timestamp_t *t2)
|
|
{
|
|
float diff;
|
|
|
|
diff = t2->tv_sec - t1->tv_sec;
|
|
diff += (((float) t2->tv_usec - (float) t1->tv_usec) / 1000000.0f);
|
|
|
|
return diff;
|
|
}
|
|
|
|
#if 0
|
|
|
|
|
|
float diff_now(timestamp_t *t1)
|
|
{
|
|
timestamp_t now;
|
|
update_ts(&now);
|
|
return time_diff(t1, &now);
|
|
}
|
|
|
|
const char *xinet_ntop(struct sockaddr *src, char *dst, socklen_t cnt)
|
|
{
|
|
void *s;
|
|
int family;
|
|
|
|
if (src->sa_family == AF_INET6) {
|
|
s = &((struct sockaddr_in6 *) src)->sin6_addr;
|
|
family = AF_INET6;
|
|
} else if (src->sa_family == AF_INET) {
|
|
s = &((struct sockaddr_in *) src)->sin_addr;
|
|
family = AF_INET;
|
|
} else
|
|
return NULL;
|
|
|
|
return inet_ntop(family, s, dst, cnt);
|
|
}
|
|
|
|
uint64_t parse_size(const char *str)
|
|
{
|
|
char *p;
|
|
uint64_t l = strtol(str, &p, 0);
|
|
if (p == str)
|
|
return -1;
|
|
|
|
if (*p) {
|
|
if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
|
|
l *= 1024;
|
|
else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
|
|
l *= 1024*1024*1024;
|
|
else if (!strcasecmp(p, "gbit"))
|
|
l *= 1024*1024*1024/8;
|
|
else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
|
|
l *= 1024*1024;
|
|
else if (!strcasecmp(p, "mbit"))
|
|
l *= 1024*1024/8;
|
|
else if (!strcasecmp(p, "kbit"))
|
|
l *= 1024/8;
|
|
else if (strcasecmp(p, "b") != 0)
|
|
return -1;
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
#ifndef HAVE_STRDUP
|
|
char *strdup(const char *s)
|
|
{
|
|
char *t = xcalloc(1, strlen(s) + 1);
|
|
memcpy(t, s, strlen(s));
|
|
return s;
|
|
}
|
|
#endif
|
|
|
|
char *timestamp2str(timestamp_t *ts, char *buf, size_t len)
|
|
{
|
|
int i, split[5];
|
|
char *units[] = {"d", "h", "m", "s", "usec"};
|
|
time_t sec = ts->tv_sec;
|
|
|
|
#define _SPLIT(idx, unit) if ((split[idx] = sec / unit) > 0) sec %= unit
|
|
_SPLIT(0, 86400); /* days */
|
|
_SPLIT(1, 3600); /* hours */
|
|
_SPLIT(2, 60); /* minutes */
|
|
_SPLIT(3, 1); /* seconds */
|
|
#undef _SPLIT
|
|
split[4] = ts->tv_usec;
|
|
|
|
memset(buf, 0, len);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(split); i++) {
|
|
if (split[i] > 0) {
|
|
char t[64];
|
|
snprintf(t, sizeof(t), "%s%d%s",
|
|
strlen(buf) ? " " : "", split[i], units[i]);
|
|
strncat(buf, t, len - strlen(buf) - 1);
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
int parse_date(const char *str, xdate_t *dst)
|
|
{
|
|
time_t now = time(NULL);
|
|
struct tm *now_tm = localtime(&now);
|
|
const char *next;
|
|
char *p;
|
|
struct tm backup;
|
|
|
|
memset(dst, 0, sizeof(*dst));
|
|
|
|
if (strchr(str, '-')) {
|
|
next = strptime(str, "%Y-%m-%d", &dst->d_tm);
|
|
if (next == NULL ||
|
|
(*next != '\0' && *next != ' '))
|
|
goto invalid_date;
|
|
} else {
|
|
dst->d_tm.tm_mday = now_tm->tm_mday;
|
|
dst->d_tm.tm_mon = now_tm->tm_mon;
|
|
dst->d_tm.tm_year = now_tm->tm_year;
|
|
dst->d_tm.tm_wday = now_tm->tm_wday;
|
|
dst->d_tm.tm_yday = now_tm->tm_yday;
|
|
dst->d_tm.tm_isdst = now_tm->tm_isdst;
|
|
next = str;
|
|
}
|
|
|
|
if (*next == '\0')
|
|
return 0;
|
|
|
|
while (*next == ' ')
|
|
next++;
|
|
|
|
if (*next == '.')
|
|
goto read_us;
|
|
|
|
/* Make a backup, we can't rely on strptime to not screw
|
|
* up what we've got so far. */
|
|
memset(&backup, 0, sizeof(backup));
|
|
memcpy(&backup, &dst->d_tm, sizeof(backup));
|
|
|
|
next = strptime(next, "%H:%M:%S", &dst->d_tm);
|
|
if (next == NULL ||
|
|
(*next != '\0' && *next != '.'))
|
|
goto invalid_date;
|
|
|
|
dst->d_tm.tm_mday = backup.tm_mday;
|
|
dst->d_tm.tm_mon = backup.tm_mon;
|
|
dst->d_tm.tm_year = backup.tm_year;
|
|
dst->d_tm.tm_wday = backup.tm_wday;
|
|
dst->d_tm.tm_yday = backup.tm_yday;
|
|
dst->d_tm.tm_isdst = backup.tm_isdst;
|
|
|
|
if (*next == '\0')
|
|
return 0;
|
|
read_us:
|
|
if (*next == '.')
|
|
next++;
|
|
else
|
|
BUG();
|
|
|
|
dst->d_usec = strtoul(next, &p, 10);
|
|
|
|
if (*p != '\0')
|
|
goto invalid_date;
|
|
|
|
return 0;
|
|
|
|
invalid_date:
|
|
fprintf(stderr, "Invalid date \"%s\"\n", str);
|
|
return -1;
|
|
}
|
|
|
|
static inline void print_token(FILE *fd, struct db_token *tok)
|
|
{
|
|
fprintf(fd, "%s", tok->t_name);
|
|
|
|
if (tok->t_flags & DB_T_ATTR)
|
|
fprintf(fd, "<attr>");
|
|
}
|
|
|
|
void db_print_filter(FILE *fd, struct db_filter *filter)
|
|
{
|
|
if (filter->f_node)
|
|
print_token(fd, filter->f_node);
|
|
|
|
if (filter->f_group) {
|
|
fprintf(fd, ".");
|
|
print_token(fd, filter->f_group);
|
|
}
|
|
|
|
if (filter->f_item) {
|
|
fprintf(fd, ".");
|
|
print_token(fd, filter->f_item);
|
|
}
|
|
|
|
if (filter->f_attr) {
|
|
fprintf(fd, ".");
|
|
print_token(fd, filter->f_attr);
|
|
}
|
|
|
|
if (filter->f_field)
|
|
fprintf(fd, "@%s", filter->f_field);
|
|
}
|
|
|
|
void *db_filter__scan_string(const char *);
|
|
void db_filter__switch_to_buffer(void *);
|
|
int db_filter_parse(void);
|
|
|
|
struct db_filter * parse_db_filter(const char *buf)
|
|
{
|
|
struct db_filter *f;
|
|
struct db_token *tok, *t;
|
|
|
|
void *state = db_filter__scan_string(buf);
|
|
db_filter__switch_to_buffer(state);
|
|
|
|
if (db_filter_parse()) {
|
|
fprintf(stderr, "Failed to parse filter \"%s\"\n", buf);
|
|
return NULL;
|
|
}
|
|
|
|
tok = db_filter_out; /* generated by yacc */
|
|
if (tok == NULL)
|
|
return NULL;
|
|
|
|
f = xcalloc(1, sizeof(*f));
|
|
|
|
f->f_node = tok;
|
|
|
|
if (!tok->t_next)
|
|
goto out;
|
|
tok = tok->t_next;
|
|
|
|
if (tok->t_flags & DB_T_ATTR) {
|
|
fprintf(stderr, "Node may not contain an attribute field\n");
|
|
goto errout;
|
|
}
|
|
|
|
f->f_group = tok;
|
|
if (!tok->t_next)
|
|
goto out;
|
|
tok = tok->t_next;
|
|
|
|
if (tok->t_flags & DB_T_ATTR) {
|
|
fprintf(stderr, "Group may not contain an attribute field\n");
|
|
goto errout;
|
|
}
|
|
|
|
f->f_item = tok;
|
|
|
|
if (!tok->t_next)
|
|
goto out;
|
|
tok = tok->t_next;
|
|
|
|
if (tok->t_flags & DB_T_ATTR) {
|
|
if (!tok->t_name)
|
|
BUG();
|
|
f->f_field = tok->t_name;
|
|
goto out;
|
|
} else
|
|
f->f_attr = tok;
|
|
|
|
if (!tok->t_next)
|
|
goto out;
|
|
tok = tok->t_next;
|
|
|
|
if (tok->t_flags & DB_T_ATTR) {
|
|
if (!tok->t_name)
|
|
BUG();
|
|
f->f_field = tok->t_name;
|
|
} else {
|
|
fprintf(stderr, "Unexpected additional token after attribute\n");
|
|
goto errout;
|
|
}
|
|
|
|
out:
|
|
/* free unused tokens */
|
|
for (tok = tok->t_next ; tok; tok = t) {
|
|
t = tok->t_next;
|
|
if (tok->t_name)
|
|
free(tok->t_name);
|
|
free(tok);
|
|
}
|
|
|
|
return f;
|
|
|
|
errout:
|
|
free(f);
|
|
f = NULL;
|
|
tok = db_filter_out;
|
|
goto out;
|
|
}
|
|
#endif
|