mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 18:07:40 +00:00
297 lines
6.4 KiB
C
297 lines
6.4 KiB
C
|
/*
|
||
|
* Copyright (c) 2008, 2009 Nicira Networks.
|
||
|
*
|
||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||
|
* purpose with or without fee is hereby granted, provided that the above
|
||
|
* copyright notice and this permission notice appear in all copies.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include <config.h>
|
||
|
#include "util.h"
|
||
|
#include <errno.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include "coverage.h"
|
||
|
|
||
|
const char *program_name;
|
||
|
|
||
|
void
|
||
|
out_of_memory(void)
|
||
|
{
|
||
|
ovs_fatal(0, "virtual memory exhausted");
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
xcalloc(size_t count, size_t size)
|
||
|
{
|
||
|
void *p = count && size ? calloc(count, size) : malloc(1);
|
||
|
COVERAGE_INC(util_xalloc);
|
||
|
if (p == NULL) {
|
||
|
out_of_memory();
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
xmalloc(size_t size)
|
||
|
{
|
||
|
void *p = malloc(size ? size : 1);
|
||
|
COVERAGE_INC(util_xalloc);
|
||
|
if (p == NULL) {
|
||
|
out_of_memory();
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
xrealloc(void *p, size_t size)
|
||
|
{
|
||
|
p = realloc(p, size ? size : 1);
|
||
|
COVERAGE_INC(util_xalloc);
|
||
|
if (p == NULL) {
|
||
|
out_of_memory();
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
xmemdup(const void *p_, size_t size)
|
||
|
{
|
||
|
void *p = xmalloc(size);
|
||
|
memcpy(p, p_, size);
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
xmemdup0(const char *p_, size_t length)
|
||
|
{
|
||
|
char *p = xmalloc(length + 1);
|
||
|
memcpy(p, p_, length);
|
||
|
p[length] = '\0';
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
xstrdup(const char *s)
|
||
|
{
|
||
|
return xmemdup0(s, strlen(s));
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
xvasprintf(const char *format, va_list args)
|
||
|
{
|
||
|
va_list args2;
|
||
|
size_t needed;
|
||
|
char *s;
|
||
|
|
||
|
va_copy(args2, args);
|
||
|
needed = vsnprintf(NULL, 0, format, args);
|
||
|
|
||
|
s = xmalloc(needed + 1);
|
||
|
|
||
|
vsnprintf(s, needed + 1, format, args2);
|
||
|
va_end(args2);
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
x2nrealloc(void *p, size_t *n, size_t s)
|
||
|
{
|
||
|
*n = *n == 0 ? 1 : 2 * *n;
|
||
|
return xrealloc(p, *n * s);
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
xasprintf(const char *format, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
char *s;
|
||
|
|
||
|
va_start(args, format);
|
||
|
s = xvasprintf(format, args);
|
||
|
va_end(args);
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ovs_strlcpy(char *dst, const char *src, size_t size)
|
||
|
{
|
||
|
if (size > 0) {
|
||
|
size_t n = strlen(src);
|
||
|
size_t n_copy = MIN(n, size - 1);
|
||
|
memcpy(dst, src, n_copy);
|
||
|
dst[n_copy] = '\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ovs_fatal(int err_no, const char *format, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
fprintf(stderr, "%s: ", program_name);
|
||
|
va_start(args, format);
|
||
|
vfprintf(stderr, format, args);
|
||
|
va_end(args);
|
||
|
if (err_no != 0)
|
||
|
fprintf(stderr, " (%s)", strerror(err_no));
|
||
|
putc('\n', stderr);
|
||
|
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ovs_error(int err_no, const char *format, ...)
|
||
|
{
|
||
|
int save_errno = errno;
|
||
|
va_list args;
|
||
|
|
||
|
fprintf(stderr, "%s: ", program_name);
|
||
|
va_start(args, format);
|
||
|
vfprintf(stderr, format, args);
|
||
|
va_end(args);
|
||
|
if (err_no != 0)
|
||
|
fprintf(stderr, " (%s)", strerror(err_no));
|
||
|
putc('\n', stderr);
|
||
|
|
||
|
errno = save_errno;
|
||
|
}
|
||
|
|
||
|
/* Sets program_name based on 'argv0'. Should be called at the beginning of
|
||
|
* main(), as "set_program_name(argv[0]);". */
|
||
|
void set_program_name(const char *argv0)
|
||
|
{
|
||
|
const char *slash = strrchr(argv0, '/');
|
||
|
program_name = slash ? slash + 1 : argv0;
|
||
|
}
|
||
|
|
||
|
/* Print the version information for the program. */
|
||
|
void
|
||
|
ovs_print_version(char *date, char *time,
|
||
|
uint8_t min_ofp, uint8_t max_ofp)
|
||
|
{
|
||
|
printf("%s (Open vSwitch) "VERSION BUILDNR"\n", program_name);
|
||
|
printf("Compiled %s %s\n", date, time);
|
||
|
if (min_ofp || max_ofp) {
|
||
|
printf("OpenFlow versions %#x:%#x\n", min_ofp, max_ofp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Writes the 'size' bytes in 'buf' to 'stream' as hex bytes arranged 16 per
|
||
|
* line. Numeric offsets are also included, starting at 'ofs' for the first
|
||
|
* byte in 'buf'. If 'ascii' is true then the corresponding ASCII characters
|
||
|
* are also rendered alongside. */
|
||
|
void
|
||
|
ovs_hex_dump(FILE *stream, const void *buf_, size_t size,
|
||
|
uintptr_t ofs, bool ascii)
|
||
|
{
|
||
|
const uint8_t *buf = buf_;
|
||
|
const size_t per_line = 16; /* Maximum bytes per line. */
|
||
|
|
||
|
while (size > 0)
|
||
|
{
|
||
|
size_t start, end, n;
|
||
|
size_t i;
|
||
|
|
||
|
/* Number of bytes on this line. */
|
||
|
start = ofs % per_line;
|
||
|
end = per_line;
|
||
|
if (end - start > size)
|
||
|
end = start + size;
|
||
|
n = end - start;
|
||
|
|
||
|
/* Print line. */
|
||
|
fprintf(stream, "%08jx ", (uintmax_t) ROUND_DOWN(ofs, per_line));
|
||
|
for (i = 0; i < start; i++)
|
||
|
fprintf(stream, " ");
|
||
|
for (; i < end; i++)
|
||
|
fprintf(stream, "%02hhx%c",
|
||
|
buf[i - start], i == per_line / 2 - 1? '-' : ' ');
|
||
|
if (ascii)
|
||
|
{
|
||
|
for (; i < per_line; i++)
|
||
|
fprintf(stream, " ");
|
||
|
fprintf(stream, "|");
|
||
|
for (i = 0; i < start; i++)
|
||
|
fprintf(stream, " ");
|
||
|
for (; i < end; i++) {
|
||
|
int c = buf[i - start];
|
||
|
putc(c >= 32 && c < 127 ? c : '.', stream);
|
||
|
}
|
||
|
for (; i < per_line; i++)
|
||
|
fprintf(stream, " ");
|
||
|
fprintf(stream, "|");
|
||
|
}
|
||
|
fprintf(stream, "\n");
|
||
|
|
||
|
ofs += n;
|
||
|
buf += n;
|
||
|
size -= n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_int(const char *s, int base, int *i)
|
||
|
{
|
||
|
long long ll;
|
||
|
bool ok = str_to_llong(s, base, &ll);
|
||
|
*i = ll;
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_long(const char *s, int base, long *li)
|
||
|
{
|
||
|
long long ll;
|
||
|
bool ok = str_to_llong(s, base, &ll);
|
||
|
*li = ll;
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_llong(const char *s, int base, long long *x)
|
||
|
{
|
||
|
int save_errno = errno;
|
||
|
char *tail;
|
||
|
errno = 0;
|
||
|
*x = strtoll(s, &tail, base);
|
||
|
if (errno == EINVAL || errno == ERANGE || tail == s || *tail != '\0') {
|
||
|
errno = save_errno;
|
||
|
*x = 0;
|
||
|
return false;
|
||
|
} else {
|
||
|
errno = save_errno;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_uint(const char *s, int base, unsigned int *u)
|
||
|
{
|
||
|
return str_to_int(s, base, (int *) u);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_ulong(const char *s, int base, unsigned long *ul)
|
||
|
{
|
||
|
return str_to_long(s, base, (long *) ul);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
str_to_ullong(const char *s, int base, unsigned long long *ull)
|
||
|
{
|
||
|
return str_to_llong(s, base, (long long *) ull);
|
||
|
}
|