1: /*
2: * utils.c General purpose utilities
3: *
4: * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5: * Copyright (c) 2013 Red Hat, Inc.
6: *
7: * Permission is hereby granted, free of charge, to any person obtaining a
8: * copy of this software and associated documentation files (the "Software"),
9: * to deal in the Software without restriction, including without limitation
10: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11: * and/or sell copies of the Software, and to permit persons to whom the
12: * Software is furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included
15: * in all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23: * DEALINGS IN THE SOFTWARE.
24: */
25:
26: #include <bmon/bmon.h>
27: #include <bmon/conf.h>
28: #include <bmon/utils.h>
29:
30: void *xcalloc(size_t n, size_t s)
31: {
32: void *d = calloc(n, s);
33:
34: if (NULL == d) {
35: fprintf(stderr, "xalloc: Out of memory\n");
36: exit(ENOMEM);
37: }
38:
39: return d;
40: }
41:
42: void *xrealloc(void *p, size_t s)
43: {
44: void *d = realloc(p, s);
45:
46: if (NULL == d) {
47: fprintf(stderr, "xrealloc: Out of memory!\n");
48: exit(ENOMEM);
49: }
50:
51: return d;
52: }
53:
54: void xfree(void *d)
55: {
56: if (d)
57: free(d);
58: }
59:
60: float timestamp_to_float(timestamp_t *src)
61: {
62: return (float) src->tv_sec + ((float) src->tv_usec / 1000000.0f);
63: }
64:
65: int64_t timestamp_to_int(timestamp_t *src)
66: {
67: return (src->tv_sec * 1000000ULL) + src->tv_usec;
68: }
69:
70: void float_to_timestamp(timestamp_t *dst, float src)
71: {
72: dst->tv_sec = (time_t) src;
73: dst->tv_usec = (src - ((float) ((time_t) src))) * 1000000.0f;
74: }
75:
76: void timestamp_add(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
77: {
78: dst->tv_sec = src1->tv_sec + src2->tv_sec;
79: dst->tv_usec = src1->tv_usec + src2->tv_usec;
80:
81: if (dst->tv_usec >= 1000000) {
82: dst->tv_sec++;
83: dst->tv_usec -= 1000000;
84: }
85: }
86:
87: void timestamp_sub(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
88: {
89: dst->tv_sec = src1->tv_sec - src2->tv_sec;
90: dst->tv_usec = src1->tv_usec - src2->tv_usec;
91: if (dst->tv_usec < 0) {
92: dst->tv_sec--;
93: dst->tv_usec += 1000000;
94: }
95: }
96:
97: int timestamp_le(timestamp_t *a, timestamp_t *b)
98: {
99: if (a->tv_sec > b->tv_sec)
100: return 0;
101:
102: if (a->tv_sec < b->tv_sec || a->tv_usec <= b->tv_usec)
103: return 1;
104:
105: return 0;
106: }
107:
108: int timestamp_is_negative(timestamp_t *ts)
109: {
110: return (ts->tv_sec < 0 || ts->tv_usec < 0);
111: }
112:
113: void update_timestamp(timestamp_t *dst)
114: {
115: struct timeval tv;
116:
117: gettimeofday(&tv, NULL);
118:
119: dst->tv_sec = tv.tv_sec;
120: dst->tv_usec = tv.tv_usec;
121: }
122:
123: void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2)
124: {
125: ts1->tv_sec = ts2->tv_sec;
126: ts2->tv_usec = ts2->tv_usec;
127: }
128:
129: float timestamp_diff(timestamp_t *t1, timestamp_t *t2)
130: {
131: float diff;
132:
133: diff = t2->tv_sec - t1->tv_sec;
134: diff += (((float) t2->tv_usec - (float) t1->tv_usec) / 1000000.0f);
135:
136: return diff;
137: }
138:
139: #if 0
140:
141:
142: float diff_now(timestamp_t *t1)
143: {
144: timestamp_t now;
145: update_ts(&now);
146: return time_diff(t1, &now);
147: }
148:
149: const char *xinet_ntop(struct sockaddr *src, char *dst, socklen_t cnt)
150: {
151: void *s;
152: int family;
153:
154: if (src->sa_family == AF_INET6) {
155: s = &((struct sockaddr_in6 *) src)->sin6_addr;
156: family = AF_INET6;
157: } else if (src->sa_family == AF_INET) {
158: s = &((struct sockaddr_in *) src)->sin_addr;
159: family = AF_INET;
160: } else
161: return NULL;
162:
163: return inet_ntop(family, s, dst, cnt);
164: }
165:
166: uint64_t parse_size(const char *str)
167: {
168: char *p;
169: uint64_t l = strtol(str, &p, 0);
170: if (p == str)
171: return -1;
172:
173: if (*p) {
174: if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
175: l *= 1024;
176: else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
177: l *= 1024*1024*1024;
178: else if (!strcasecmp(p, "gbit"))
179: l *= 1024*1024*1024/8;
180: else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
181: l *= 1024*1024;
182: else if (!strcasecmp(p, "mbit"))
183: l *= 1024*1024/8;
184: else if (!strcasecmp(p, "kbit"))
185: l *= 1024/8;
186: else if (strcasecmp(p, "b") != 0)
187: return -1;
188: }
189:
190: return l;
191: }
192:
193: #ifndef HAVE_STRDUP
194: char *strdup(const char *s)
195: {
196: char *t = xcalloc(1, strlen(s) + 1);
197: memcpy(t, s, strlen(s));
198: return s;
199: }
200: #endif
201:
202: char *timestamp2str(timestamp_t *ts, char *buf, size_t len)
203: {
204: int i, split[5];
205: char *units[] = {"d", "h", "m", "s", "usec"};
206: time_t sec = ts->tv_sec;
207:
208: #define _SPLIT(idx, unit) if ((split[idx] = sec / unit) > 0) sec %= unit
209: _SPLIT(0, 86400); /* days */
210: _SPLIT(1, 3600); /* hours */
211: _SPLIT(2, 60); /* minutes */
212: _SPLIT(3, 1); /* seconds */
213: #undef _SPLIT
214: split[4] = ts->tv_usec;
215:
216: memset(buf, 0, len);
217:
218: for (i = 0; i < ARRAY_SIZE(split); i++) {
219: if (split[i] > 0) {
220: char t[64];
221: snprintf(t, sizeof(t), "%s%d%s",
222: strlen(buf) ? " " : "", split[i], units[i]);
223: strncat(buf, t, len - strlen(buf) - 1);
224: }
225: }
226:
227: return buf;
228: }
229:
230: int parse_date(const char *str, xdate_t *dst)
231: {
232: time_t now = time(NULL);
233: struct tm *now_tm = localtime(&now);
234: const char *next;
235: char *p;
236: struct tm backup;
237:
238: memset(dst, 0, sizeof(*dst));
239:
240: if (strchr(str, '-')) {
241: next = strptime(str, "%Y-%m-%d", &dst->d_tm);
242: if (next == NULL ||
243: (*next != '\0' && *next != ' '))
244: goto invalid_date;
245: } else {
246: dst->d_tm.tm_mday = now_tm->tm_mday;
247: dst->d_tm.tm_mon = now_tm->tm_mon;
248: dst->d_tm.tm_year = now_tm->tm_year;
249: dst->d_tm.tm_wday = now_tm->tm_wday;
250: dst->d_tm.tm_yday = now_tm->tm_yday;
251: dst->d_tm.tm_isdst = now_tm->tm_isdst;
252: next = str;
253: }
254:
255: if (*next == '\0')
256: return 0;
257:
258: while (*next == ' ')
259: next++;
260:
261: if (*next == '.')
262: goto read_us;
263:
264: /* Make a backup, we can't rely on strptime to not screw
265: * up what we've got so far. */
266: memset(&backup, 0, sizeof(backup));
267: memcpy(&backup, &dst->d_tm, sizeof(backup));
268:
269: next = strptime(next, "%H:%M:%S", &dst->d_tm);
270: if (next == NULL ||
271: (*next != '\0' && *next != '.'))
272: goto invalid_date;
273:
274: dst->d_tm.tm_mday = backup.tm_mday;
275: dst->d_tm.tm_mon = backup.tm_mon;
276: dst->d_tm.tm_year = backup.tm_year;
277: dst->d_tm.tm_wday = backup.tm_wday;
278: dst->d_tm.tm_yday = backup.tm_yday;
279: dst->d_tm.tm_isdst = backup.tm_isdst;
280:
281: if (*next == '\0')
282: return 0;
283: read_us:
284: if (*next == '.')
285: next++;
286: else
287: BUG();
288:
289: dst->d_usec = strtoul(next, &p, 10);
290:
291: if (*p != '\0')
292: goto invalid_date;
293:
294: return 0;
295:
296: invalid_date:
297: fprintf(stderr, "Invalid date \"%s\"\n", str);
298: return -1;
299: }
300:
301: static inline void print_token(FILE *fd, struct db_token *tok)
302: {
303: fprintf(fd, "%s", tok->t_name);
304:
305: if (tok->t_flags & DB_T_ATTR)
306: fprintf(fd, "<attr>");
307: }
308:
309: void db_print_filter(FILE *fd, struct db_filter *filter)
310: {
311: if (filter->f_node)
312: print_token(fd, filter->f_node);
313:
314: if (filter->f_group) {
315: fprintf(fd, ".");
316: print_token(fd, filter->f_group);
317: }
318:
319: if (filter->f_item) {
320: fprintf(fd, ".");
321: print_token(fd, filter->f_item);
322: }
323:
324: if (filter->f_attr) {
325: fprintf(fd, ".");
326: print_token(fd, filter->f_attr);
327: }
328:
329: if (filter->f_field)
330: fprintf(fd, "@%s", filter->f_field);
331: }
332:
333: void *db_filter__scan_string(const char *);
334: void db_filter__switch_to_buffer(void *);
335: int db_filter_parse(void);
336:
337: struct db_filter * parse_db_filter(const char *buf)
338: {
339: struct db_filter *f;
340: struct db_token *tok, *t;
341:
342: void *state = db_filter__scan_string(buf);
343: db_filter__switch_to_buffer(state);
344:
345: if (db_filter_parse()) {
346: fprintf(stderr, "Failed to parse filter \"%s\"\n", buf);
347: return NULL;
348: }
349:
350: tok = db_filter_out; /* generated by yacc */
351: if (tok == NULL)
352: return NULL;
353:
354: f = xcalloc(1, sizeof(*f));
355:
356: f->f_node = tok;
357:
358: if (!tok->t_next)
359: goto out;
360: tok = tok->t_next;
361:
362: if (tok->t_flags & DB_T_ATTR) {
363: fprintf(stderr, "Node may not contain an attribute field\n");
364: goto errout;
365: }
366:
367: f->f_group = tok;
368: if (!tok->t_next)
369: goto out;
370: tok = tok->t_next;
371:
372: if (tok->t_flags & DB_T_ATTR) {
373: fprintf(stderr, "Group may not contain an attribute field\n");
374: goto errout;
375: }
376:
377: f->f_item = tok;
378:
379: if (!tok->t_next)
380: goto out;
381: tok = tok->t_next;
382:
383: if (tok->t_flags & DB_T_ATTR) {
384: if (!tok->t_name)
385: BUG();
386: f->f_field = tok->t_name;
387: goto out;
388: } else
389: f->f_attr = tok;
390:
391: if (!tok->t_next)
392: goto out;
393: tok = tok->t_next;
394:
395: if (tok->t_flags & DB_T_ATTR) {
396: if (!tok->t_name)
397: BUG();
398: f->f_field = tok->t_name;
399: } else {
400: fprintf(stderr, "Unexpected additional token after attribute\n");
401: goto errout;
402: }
403:
404: out:
405: /* free unused tokens */
406: for (tok = tok->t_next ; tok; tok = t) {
407: t = tok->t_next;
408: if (tok->t_name)
409: free(tok->t_name);
410: free(tok);
411: }
412:
413: return f;
414:
415: errout:
416: free(f);
417: f = NULL;
418: tok = db_filter_out;
419: goto out;
420: }
421: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>