517 lines
11 KiB
C
517 lines
11 KiB
C
/*
|
|
* Cisco router simulation platform.
|
|
* Copyright (c) 2005,2006 Christophe Fillot. All rights reserved.
|
|
*
|
|
* Utility functions.
|
|
*/
|
|
/*
|
|
* Copyright (C) yajin 2008 <yajinzhou@gmail.com >
|
|
*
|
|
* This file is part of the virtualmips distribution.
|
|
* See LICENSE file for terms of the license.
|
|
*
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#ifdef __CYGWIN__
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#include "utils.h"
|
|
|
|
extern FILE *log_file;
|
|
|
|
unsigned int get_file_size (const char *file_path)
|
|
{
|
|
struct stat statbuf;
|
|
if (stat (file_path, &statbuf) == -1) {
|
|
printf ("Get stat on %s Error:%s\n", file_path, strerror (errno));
|
|
return (0);
|
|
}
|
|
if (S_ISDIR (statbuf.st_mode))
|
|
return (0);
|
|
if (S_ISREG (statbuf.st_mode))
|
|
return (statbuf.st_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Dynamic sprintf */
|
|
char *dyn_sprintf (const char *fmt, ...)
|
|
{
|
|
int n, size = 512;
|
|
va_list ap;
|
|
char *p, *p2;
|
|
|
|
if ((p = malloc (size)) == NULL) {
|
|
perror ("dyn_sprintf: malloc");
|
|
return NULL;
|
|
}
|
|
|
|
for (;;) {
|
|
/* Try to print in the allocated space */
|
|
va_start (ap, fmt);
|
|
n = vsnprintf (p, size, fmt, ap);
|
|
va_end (ap);
|
|
|
|
/* If that worked, return the string */
|
|
if ((n > -1) && (n < size))
|
|
return p;
|
|
|
|
/* Else try again with more space. */
|
|
if (n > -1)
|
|
size = n + 1;
|
|
else
|
|
size *= 2;
|
|
free (p);
|
|
if ((p2 = malloc (size)) == NULL) {
|
|
perror ("dyn_sprintf: realloc");
|
|
return NULL;
|
|
}
|
|
|
|
p = p2;
|
|
}
|
|
free (p2);
|
|
}
|
|
|
|
/* Split a string */
|
|
int m_strsplit (char *str, char delim, char **array, int max_count)
|
|
{
|
|
int i, pos = 0;
|
|
size_t len;
|
|
char *ptr;
|
|
|
|
for (i = 0; i < max_count; i++)
|
|
array[i] = NULL;
|
|
|
|
do {
|
|
if (pos == max_count)
|
|
goto error;
|
|
|
|
ptr = strchr (str, delim);
|
|
if (!ptr)
|
|
ptr = str + strlen (str);
|
|
|
|
len = ptr - str;
|
|
|
|
if (!(array[pos] = malloc (len + 1)))
|
|
goto error;
|
|
|
|
memcpy (array[pos], str, len);
|
|
array[pos][len] = 0;
|
|
|
|
str = ptr + 1;
|
|
pos++;
|
|
}
|
|
while (*ptr);
|
|
return (pos);
|
|
|
|
error:
|
|
for (i = 0; i < max_count; i++)
|
|
free (array[i]);
|
|
return (-1);
|
|
}
|
|
|
|
/* Tokenize a string */
|
|
int m_strtok (char *str, char delim, char **array, int max_count)
|
|
{
|
|
int i, pos = 0;
|
|
size_t len;
|
|
char *ptr;
|
|
|
|
for (i = 0; i < max_count; i++)
|
|
array[i] = NULL;
|
|
|
|
do {
|
|
if (pos == max_count)
|
|
goto error;
|
|
|
|
ptr = strchr (str, delim);
|
|
if (!ptr)
|
|
ptr = str + strlen (str);
|
|
|
|
len = ptr - str;
|
|
|
|
if (!(array[pos] = malloc (len + 1)))
|
|
goto error;
|
|
|
|
memcpy (array[pos], str, len);
|
|
array[pos][len] = 0;
|
|
|
|
while (*ptr == delim)
|
|
ptr++;
|
|
|
|
str = ptr;
|
|
pos++;
|
|
}
|
|
while (*ptr);
|
|
|
|
return (pos);
|
|
|
|
error:
|
|
for (i = 0; i < max_count; i++)
|
|
free (array[i]);
|
|
return (-1);
|
|
}
|
|
|
|
/* Quote a string */
|
|
char *m_strquote (char *buffer, size_t buf_len, char *str)
|
|
{
|
|
char *p;
|
|
|
|
if (!(p = strpbrk (str, " \t\"'")))
|
|
return str;
|
|
|
|
snprintf (buffer, buf_len, "\"%s\"", str);
|
|
return buffer;
|
|
}
|
|
|
|
/* Ugly function that dumps a structure in hexa and ascii. */
|
|
void mem_dump (FILE * f_output, u_char * pkt, u_int len)
|
|
{
|
|
u_int x, i = 0, tmp;
|
|
|
|
while (i < len) {
|
|
if ((len - i) > 16)
|
|
x = 16;
|
|
else
|
|
x = len - i;
|
|
|
|
fprintf (f_output, "%4.4x: ", i);
|
|
|
|
for (tmp = 0; tmp < x; tmp++)
|
|
fprintf (f_output, "%2.2x ", pkt[i + tmp]);
|
|
for (tmp = x; tmp < 16; tmp++)
|
|
fprintf (f_output, " ");
|
|
|
|
for (tmp = 0; tmp < x; tmp++) {
|
|
char c = pkt[i + tmp];
|
|
|
|
if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))
|
|
|| ((c >= '0') && (c <= '9')))
|
|
fprintf (f_output, "%c", c);
|
|
else
|
|
fputs (".", f_output);
|
|
}
|
|
|
|
i += x;
|
|
fprintf (f_output, "\n");
|
|
}
|
|
|
|
fprintf (f_output, "\n");
|
|
}
|
|
|
|
/* Logging function */
|
|
void m_flog (FILE * fd, char *module, char *fmt, va_list ap)
|
|
{
|
|
struct timeval now;
|
|
static char buf[256];
|
|
time_t ct;
|
|
|
|
gettimeofday (&now, 0);
|
|
ct = now.tv_sec;
|
|
strftime (buf, sizeof (buf), "%b %d %H:%M:%S", localtime (&ct));
|
|
if (fd) {
|
|
fprintf (fd, "%s.%03ld %s: ", buf, (long) now.tv_usec / 1000, module);
|
|
vfprintf (fd, fmt, ap);
|
|
fflush (fd);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/* Logging function */
|
|
void m_log (char *module, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, fmt);
|
|
m_flog (log_file, module, fmt, ap);
|
|
va_end (ap);
|
|
}
|
|
#endif
|
|
|
|
/* Returns a line from specified file (remove trailing '\n') */
|
|
char *m_fgets (char *buffer, int size, FILE * fd)
|
|
{
|
|
int len;
|
|
|
|
buffer[0] = '\0';
|
|
if (fgets (buffer, size, fd) == NULL)
|
|
return NULL;
|
|
|
|
len = strlen (buffer);
|
|
if (len == 0)
|
|
return NULL;
|
|
|
|
/* remove trailing '\n' */
|
|
if (buffer[len - 1] == '\n')
|
|
buffer[len - 1] = '\0';
|
|
|
|
return buffer;
|
|
}
|
|
|
|
/* Read a file and returns it in a buffer */
|
|
ssize_t m_read_file (char *filename, char **buffer)
|
|
{
|
|
char tmp[256], *ptr, *nptr;
|
|
size_t len, tot_len;
|
|
FILE *fd;
|
|
|
|
*buffer = ptr = NULL;
|
|
tot_len = 0;
|
|
|
|
/* Open file for reading */
|
|
if ((fd = fopen (filename, "r")) == NULL)
|
|
return (-1);
|
|
|
|
while ((len = fread (tmp, 1, sizeof (tmp), fd)) > 0) {
|
|
/* Reallocate memory */
|
|
nptr = realloc (ptr, tot_len + len + 1);
|
|
if (nptr == NULL) {
|
|
if (ptr)
|
|
free (ptr);
|
|
fclose (fd);
|
|
return (-1);
|
|
}
|
|
|
|
ptr = nptr;
|
|
|
|
/* Ok, memory could be allocated */
|
|
memcpy (&ptr[tot_len], tmp, len);
|
|
tot_len += len;
|
|
}
|
|
|
|
fclose (fd);
|
|
*buffer = ptr;
|
|
return (tot_len);
|
|
}
|
|
|
|
/* Allocate aligned memory */
|
|
void *m_memalign (size_t boundary, size_t size)
|
|
{
|
|
void *p;
|
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
if (posix_memalign ((void *) &p, boundary, size))
|
|
#else
|
|
#if defined(__CYGWIN__) || defined(SUNOS)
|
|
if (!(p = memalign (boundary, size)))
|
|
#else
|
|
if (!(p = malloc (size)))
|
|
#endif
|
|
#endif
|
|
return NULL;
|
|
|
|
assert (((m_iptr_t) p & (boundary - 1)) == 0);
|
|
return p;
|
|
}
|
|
|
|
/* Block specified signal for calling thread */
|
|
int m_signal_block (int sig)
|
|
{
|
|
sigset_t sig_mask;
|
|
sigemptyset (&sig_mask);
|
|
sigaddset (&sig_mask, sig);
|
|
return (pthread_sigmask (SIG_BLOCK, &sig_mask, NULL));
|
|
}
|
|
|
|
/* Unblock specified signal for calling thread */
|
|
int m_signal_unblock (int sig)
|
|
{
|
|
sigset_t sig_mask;
|
|
sigemptyset (&sig_mask);
|
|
sigaddset (&sig_mask, sig);
|
|
return (pthread_sigmask (SIG_UNBLOCK, &sig_mask, NULL));
|
|
}
|
|
|
|
/* Set non-blocking mode on a file descriptor */
|
|
int m_fd_set_non_block (int fd)
|
|
{
|
|
int flags;
|
|
|
|
if ((flags = fcntl (fd, F_GETFL, 0)) < 1)
|
|
return (-1);
|
|
|
|
return (fcntl (fd, F_SETFL, flags | O_NONBLOCK));
|
|
}
|
|
|
|
/* Map a memory zone from a file */
|
|
u_char *memzone_map_file (int fd, size_t len)
|
|
{
|
|
return (mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
|
(off_t) 0));
|
|
}
|
|
|
|
/* Map a memory zone from a file, with copy-on-write (COW) */
|
|
u_char *memzone_map_cow_file (int fd, size_t len)
|
|
{
|
|
return (mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd,
|
|
(off_t) 0));
|
|
}
|
|
|
|
/* Create a file to serve as a memory zone */
|
|
int memzone_create_file (char *filename, size_t len, u_char ** ptr)
|
|
{
|
|
int fd;
|
|
|
|
if ((fd = open (filename, O_CREAT | O_RDWR, S_IRWXU)) == -1) {
|
|
perror ("memzone_create_file: open");
|
|
return (-1);
|
|
}
|
|
|
|
if (ftruncate (fd, len) == -1) {
|
|
perror ("memzone_create_file: ftruncate");
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
|
|
*ptr = memzone_map_file (fd, len);
|
|
|
|
if (!*ptr) {
|
|
close (fd);
|
|
fd = -1;
|
|
}
|
|
|
|
return (fd);
|
|
}
|
|
|
|
/* Open a file to serve as a COW memory zone */
|
|
int memzone_open_cow_file (char *filename, size_t len, u_char ** ptr)
|
|
{
|
|
int fd;
|
|
|
|
if ((fd = open (filename, O_RDWR, S_IRWXU)) == -1) {
|
|
perror ("memzone_open_file: open");
|
|
return (-1);
|
|
}
|
|
|
|
*ptr = memzone_map_cow_file (fd, len);
|
|
|
|
if (!*ptr) {
|
|
close (fd);
|
|
fd = -1;
|
|
}
|
|
|
|
return (fd);
|
|
}
|
|
|
|
/* Open a file and map it in memory */
|
|
int memzone_open_file (char *filename, u_char ** ptr, off_t * fsize)
|
|
{
|
|
struct stat fprop;
|
|
int fd;
|
|
|
|
if ((fd = open (filename, O_RDWR, S_IRWXU)) == -1)
|
|
return (-1);
|
|
|
|
if (fstat (fd, &fprop) == -1)
|
|
goto err_fstat;
|
|
|
|
*fsize = fprop.st_size;
|
|
if (!(*ptr = memzone_map_file (fd, *fsize)))
|
|
goto err_mmap;
|
|
|
|
return (fd);
|
|
|
|
err_mmap:
|
|
err_fstat:
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
|
|
/* Compute NVRAM checksum */
|
|
m_uint16_t nvram_cksum (m_uint16_t * ptr, size_t count)
|
|
{
|
|
m_uint32_t sum = 0;
|
|
|
|
while (count > 1) {
|
|
sum = sum + ntohs (*ptr);
|
|
ptr++;
|
|
count -= sizeof (m_uint16_t);
|
|
}
|
|
|
|
if (count > 0)
|
|
sum = sum + ((ntohs (*ptr) & 0xFF) << 8);
|
|
|
|
while (sum >> 16)
|
|
sum = (sum & 0xffff) + (sum >> 16);
|
|
|
|
return (~sum);
|
|
}
|
|
|
|
/* Byte-swap a memory block */
|
|
void mem_bswap32 (void *ptr, size_t len)
|
|
{
|
|
m_uint32_t *p = ptr;
|
|
size_t count = len >> 2;
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++, p++)
|
|
*p = swap32 (*p);
|
|
}
|
|
|
|
/* Reverse a byte */
|
|
m_uint8_t m_reverse_u8 (m_uint8_t val)
|
|
{
|
|
m_uint8_t res = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
if (val & (1 << i))
|
|
res |= 1 << (7 - i);
|
|
|
|
return (res);
|
|
}
|
|
|
|
void SubstituteLLx (char *out, const char *text, int maxlen)
|
|
{
|
|
int i;
|
|
for (i = 0; i < maxlen && text[i]; i++) {
|
|
out[i] = text[i];
|
|
}
|
|
out[i] = text[i];
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Debug
|
|
* Print a debug message, if flag is enabled. Like printf,
|
|
* only with an extra argument on the front.
|
|
* to output debug infomation , you should excute "simos -d [flag]"
|
|
****************************************************************/
|
|
void Debug (char flag, char *format, ...)
|
|
{
|
|
// if (DebugIsEnabled(flag)) {
|
|
char llformat[1024];
|
|
va_list ap;
|
|
va_start (ap, format);
|
|
|
|
SubstituteLLx (llformat, format, 1024);
|
|
|
|
/* Make this go to stderr also... */
|
|
vfprintf (stderr, llformat, ap);
|
|
|
|
//vCPUPrint(llformat, ap);
|
|
fprintf (stderr, "\r");
|
|
fflush (stderr);
|
|
va_end (ap);
|
|
|
|
//}
|
|
}
|