298 lines
6.9 KiB
C
298 lines
6.9 KiB
C
/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
|
|
* Junior University
|
|
*
|
|
* We are making the OpenFlow specification and associated documentation
|
|
* (Software) available for public use and benefit with the expectation
|
|
* that others will use, modify and enhance the Software and contribute
|
|
* those enhancements back to the community. However, since we would
|
|
* like to make the Software available for broadest use, with as few
|
|
* restrictions as possible permission is hereby granted, free of
|
|
* charge, to any person obtaining a copy of this Software to deal in
|
|
* the Software under the copyrights 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.
|
|
*
|
|
* The name and trademarks of copyright holder(s) may NOT be used in
|
|
* advertising or publicity pertaining to the Software or any
|
|
* derivatives without specific, written prior permission.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include "util.h"
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
const char *program_name;
|
|
|
|
void
|
|
out_of_memory(void)
|
|
{
|
|
ofp_fatal(0, "virtual memory exhausted");
|
|
}
|
|
|
|
void *
|
|
xcalloc(size_t count, size_t size)
|
|
{
|
|
void *p = count && size ? calloc(count, size) : malloc(1);
|
|
if (p == NULL) {
|
|
out_of_memory();
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *
|
|
xmalloc(size_t size)
|
|
{
|
|
void *p = malloc(size ? size : 1);
|
|
if (p == NULL) {
|
|
out_of_memory();
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *
|
|
xrealloc(void *p, size_t size)
|
|
{
|
|
p = realloc(p, size ? size : 1);
|
|
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
|
|
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
|
|
ofp_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
|
|
ofp_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;
|
|
}
|
|
|
|
/* 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
|
|
ofp_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);
|
|
}
|