bitkeeper revision 1.1026.1.2 (40e15b09oBOK6QWmjoE3IKmAR5xlVA)

Merge http://xen.bkbits.net:8080/xeno-unstable.bk
into gandalf.hpl.hp.com:/var/bk/xeno-unstable.bk
This commit is contained in:
xenbk@gandalf.hpl.hp.com committed 2004-06-29 12:05:29 +00:00
commit 3cffa5ecd2
62 files changed
+8369 -695

No files matched your search

+40
View File
@@ -164,6 +164,44 @@
40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py
40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults
40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd
40e033325Sjqs-_4TuzeUEprP_gYFg tools/lib/allocate.c
40e03332KYz7o1bn2MG_KPbBlyoIMA tools/lib/allocate.h
40e03332IyRttYoXKoJla5qCC514SQ tools/lib/debug.h
40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/lib/enum.c
40e03332wwMVxfobgA1PSMTSAGLiCw tools/lib/enum.h
40e03332p5Dc_owJQRuN72ymJZddFQ tools/lib/file_stream.c
40e03332jWfB2viAhLSkq1WK0r_iDQ tools/lib/file_stream.h
40e03332rUjNMGg11n2rN6V4DCrvOg tools/lib/gzip_stream.c
40e033321O5Qg22haLoq5lpmk4tooQ tools/lib/gzip_stream.h
40e03332QrTR96tc6yS2rMBpd2mq1A tools/lib/hash_table.c
40e033325KoIb0d_uy8s7b5DUR9fPQ tools/lib/hash_table.h
40e03332ihnBGzHykVwZnFmkAppb4g tools/lib/iostream.c
40e03332UGwbLR4wsw4ft14p0Yw5pg tools/lib/iostream.h
40e0333245DLDzJemeSVBLuutHtzEQ tools/lib/kernel_stream.c
40e03332aK0GkgpDdc-PVTkWKTeOBg tools/lib/kernel_stream.h
40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/lib/lexis.c
40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/lib/lexis.h
40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/lib/lzi_stream.c
40e0333233voTffE4cJSMGJARfiSSQ tools/lib/lzi_stream.h
40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/lib/lzo_stream.c
40e03332InJaiLfpDcIXBy2fI0RFGQ tools/lib/lzo_stream.h
40e03332a5SCuRsejHStTuWzMQNv8Q tools/lib/marshal.c
40e03332TwKyJrZQiiQfNq4vc2hpgw tools/lib/marshal.h
40e033328ccHlJuTR1FswYL_EC6LFA tools/lib/socket_stream.c
40e03332P0KVQGkmahj47aafo1X0nA tools/lib/socket_stream.h
40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/lib/string_stream.c
40e03332-VtK6_OZa1vMHXFil8uq6w tools/lib/string_stream.h
40e03332dDtczi6YX7_mMxhYjJeAdQ tools/lib/sxpr.c
40e03332QPuyNKDOTIYVvkwK5qO-vg tools/lib/sxpr.h
40e03332Pi0_osJ3XPBi38ADPqdl4A tools/lib/sxpr_parser.c
40e033324v5QFMvWEXXzv38uUT9kHg tools/lib/sxpr_parser.h
40e03332gKUInsqtxQOV4mPiMqf_dg tools/lib/sys_ctype.h
40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/lib/sys_net.c
40e03332lQHvQHw4Rh7VsT1_sui29A tools/lib/sys_net.h
40e033321smklZd7bDSdWvQCeIshtg tools/lib/sys_string.c
40e03332h5V611rRWURRLqb1Ekatxg tools/lib/sys_string.h
40e03332u4q5kgF0N7RfqB4s0pZVew tools/lib/xdr.c
40e03332hY16nfRXF4gGd5S1aUJUBw tools/lib/xdr.h
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
@@ -185,6 +223,8 @@
3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/xc/lib/xc_domain.c
40278d99BLsfUv3qxv0I8C1sClZ0ow tools/xc/lib/xc_elf.h
403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/xc/lib/xc_evtchn.c
40e03333Eegw8czSWvHsbKxrRZJjRA tools/xc/lib/xc_io.c
40e03333vrWGbLAhyJjXlqCHaJt7eA tools/xc/lib/xc_io.h
3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/xc/lib/xc_linux_build.c
3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/xc/lib/xc_linux_restore.c
3fbba6db7li3FJiABYtCmuGxOJxEGw tools/xc/lib/xc_linux_save.c
+21 -2
View File
@@ -3,8 +3,8 @@
*.pyc
*.so
*.so.*
*.tar.gz
*.tar.bz2
*.tar.gz
*~
BitKeeper/*/*
PENDING/*
@@ -12,15 +12,34 @@ TAGS
extras/mini-os/h/hypervisor-ifs
install
install/*
patches/*
linux-*-xen*/*
linux-2.4.26-xen/*
linux-xen-sparse
patches/*
tools/*/build/lib*/*.py
tools/balloon/balloon
tools/misc/miniterm/miniterm
tools/misc/xen_cpuperf
tools/misc/xen_log
tools/misc/xen_read_console
tools/xc/lib/.allocate.o.d
tools/xc/lib/.file_stream.o.d
tools/xc/lib/.gzip_stream.o.d
tools/xc/lib/.iostream.o.d
tools/xc/lib/.sys_net.o.d
tools/xc/lib/.sys_string.o.d
tools/xc/lib/.xc_atropos.o.d
tools/xc/lib/.xc_bvtsched.o.d
tools/xc/lib/.xc_domain.o.d
tools/xc/lib/.xc_evtchn.o.d
tools/xc/lib/.xc_io.o.d
tools/xc/lib/.xc_linux_build.o.d
tools/xc/lib/.xc_linux_restore.o.d
tools/xc/lib/.xc_linux_save.o.d
tools/xc/lib/.xc_misc.o.d
tools/xc/lib/.xc_netbsd_build.o.d
tools/xc/lib/.xc_physdev.o.d
tools/xc/lib/.xc_private.o.d
tools/xentrace/xentrace
xen/drivers/pci/classlist.h
xen/drivers/pci/devlist.h
-3
View File
@@ -5,9 +5,6 @@
# This file expects the variable 'vmid' to be set.
#============================================================================
import sys
import xenctl.ip
try:
vmid = int(vmid) # convert to integer
except:
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "allocate.h"
/** @file
* Support for allocating memory.
* Usable from user code or kernel code (with __KERNEL__ defined).
* In user code will use GC if USE_GC is defined.
*/
#ifdef __KERNEL__
/*----------------------------------------------------------------------------*/
# include <linux/config.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/types.h>
# define DEFAULT_TYPE 0
# define MALLOC(n, type) kmalloc(n, type)
# define FREE(ptr) kfree(ptr)
/*----------------------------------------------------------------------------*/
#else /* ! __KERNEL__ */
# include <stdlib.h>
# include <string.h>
# define DEFAULT_TYPE 0
#ifdef USE_GC
# include "gc.h"
# define MALLOC(n, typ) GC_malloc(n)
# define FREE(ptr) (ptr=NULL)
//typedef void *GC_PTR;
//GC_PTR (*GC_oom_fn)(size_t n);
#else
# define MALLOC(n, type) malloc(n)
# define FREE(ptr) free(ptr)
#endif
/*----------------------------------------------------------------------------*/
#endif
/** Function to call when memory cannot be allocated. */
AllocateFailedFn *allocate_failed_fn = NULL;
/** Allocate memory and zero it.
* The type is only relevant when calling from kernel code,
* from user code it is ignored.
* In kernel code the values accepted by kmalloc can be used:
* GFP_USER, GFP_ATOMIC, GFP_KERNEL.
*
* @param size number of bytes to allocate
* @param type memory type to allocate (kernel only)
* @return pointer to the allocated memory or zero
* if malloc failed
*/
void *allocate_type(int size, int type){
void *p = MALLOC(size, type);
if(p){
memzero(p, size);
} else if(allocate_failed_fn){
allocate_failed_fn(size, type);
}
return p;
}
/** Allocate memory and zero it.
*
* @param size number of bytes to allocate
* @return pointer to the allocated memory or zero
* if malloc failed
*/
void *allocate(int size){
return allocate_type(size, DEFAULT_TYPE);
}
/** Free memory allocated by allocate().
* No-op if 'p' is null.
*
* @param p memory to free
*/
void deallocate(void *p){
if(p){
FREE(p);
}
}
/** Set bytes to zero.
* No-op if 'p' is null.
*
* @param p memory to zero
* @param size number of bytes to zero
*/
void memzero(void *p, int size){
if(p){
memset(p, 0, (size_t)size);
}
}
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_ALLOCATE_H_
#define _XEN_LIB_ALLOCATE_H_
/** Allocate memory for a given type, and cast. */
#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
/** Allocate memory for a given type, and cast. */
#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype))
extern void *allocate_type(int size, int type);
extern void *allocate(int size);
extern void deallocate(void *);
extern void memzero(void *p, int size);
typedef void AllocateFailedFn(int size, int type);
extern AllocateFailedFn *allocate_failed_fn;
#endif /* _XEN_LIB_ALLOCATE_H_ */
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_DEBUG_H_
#define _XEN_LIB_DEBUG_H_
#ifndef MODULE_NAME
#define MODULE_NAME ""
#endif
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/kernel.h>
#ifdef DEBUG
#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#else
#define dprintf(fmt, args...) do {} while(0)
#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
#endif
#else
#include <stdio.h>
#ifdef DEBUG
#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#else
#define dprintf(fmt, args...) do {} while(0)
#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
#endif
#endif
/** Print format for an IP address.
* See NIPQUAD(), HIPQUAD()
*/
#define IPFMT "%u.%u.%u.%u"
#endif /* ! _XEN_LIB_DEBUG_H_ */
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __KERNEL__
#include <linux/errno.h>
#else
#include <errno.h>
#endif
#include "sys_string.h"
#include "enum.h"
/** Map an enum name to its value using a table.
*
* @param name enum name
* @param defs enum definitions
* @return enum value or -1 if not known
*/
int enum_name_to_val(char *name, EnumDef *defs){
int val = -1;
for(; defs->name; defs++){
if(!strcmp(defs->name, name)){
val = defs->val;
break;
}
}
return val;
}
/** Map an enum value to its name using a table.
*
* @param val enum value
* @param defs enum definitions
* @param defs_n number of definitions
* @return enum name or NULL if not known
*/
char *enum_val_to_name(int val, EnumDef *defs){
char *name = NULL;
for(; defs->name; defs++){
if(val == defs->val){
name = defs->name;
break;
}
}
return name;
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_ENUM_H_
#define _XEN_LIB_ENUM_H_
/** Mapping of an enum value to a name. */
typedef struct EnumDef {
int val;
char *name;
} EnumDef;
extern int enum_name_to_val(char *name, EnumDef *defs);
extern char *enum_val_to_name(int val, EnumDef *defs);
#endif /* _XEN_LIB_ENUM_H_ */
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using FILE*.
*/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include "allocate.h"
#include "file_stream.h"
static int file_read(IOStream *s, void *buf, size_t n);
static int file_write(IOStream *s, const void *buf, size_t n);
static int file_error(IOStream *s);
static int file_close(IOStream *s);
static void file_free(IOStream *s);
static int file_flush(IOStream *s);
/** Methods used by a FILE* IOStream. */
static const IOMethods file_methods = {
read: file_read,
write: file_write,
error: file_error,
close: file_close,
free: file_free,
flush: file_flush,
};
/** IOStream for stdin. */
static IOStream _iostdin = {
methods: &file_methods,
data: (void*)1,
};
/** IOStream for stdout. */
static IOStream _iostdout = {
methods: &file_methods,
data: (void*)2,
};
/** IOStream for stderr. */
static IOStream _iostderr = {
methods: &file_methods,
data: (void*)3,
};
/** IOStream for stdin. */
IOStream *iostdin = &_iostdin;
/** IOStream for stdout. */
IOStream *iostdout = &_iostdout;
/** IOStream for stderr. */
IOStream *iostderr = &_iostderr;
/** Get the underlying FILE*.
*
* @param s file stream
* @return the stream s wraps
*/
static inline FILE *get_file(IOStream *s){
switch((long)s->data){
case 1: s->data = stdin; break;
case 2: s->data = stdout; break;
case 3: s->data = stderr; break;
}
return (FILE*)s->data;
}
/** Control buffering on the underlying stream, like setvbuf().
*
* @param io file stream
* @param buf buffer
* @param mode buffering mode (see man setvbuf())
* @param size buffer size
* @return 0 on success, non-zero otherwise
*/
int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
return setvbuf(get_file(io), buf, mode, size);
}
/** Write to the underlying stream using fwrite();
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to write
* @return number of bytes written
*/
static int file_write(IOStream *s, const void *buf, size_t n){
return fwrite(buf, 1, n, get_file(s));
}
/** Read from the underlying stream using fread();
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to read
* @return number of bytes read
*/
static int file_read(IOStream *s, void *buf, size_t n){
return fread(buf, 1, n, get_file(s));
}
/** Fush the underlying stream using fflush().
*
* @param s file stream
* @return 0 on success, error code otherwise
*/
static int file_flush(IOStream *s){
return fflush(get_file(s));
}
/** Check if a stream has an error.
*
* @param s file stream
* @return 1 if has an error, 0 otherwise
*/
static int file_error(IOStream *s){
return ferror(get_file(s));
}
/** Close a file stream.
*
* @param s file stream to close
* @return result of the close
*/
static int file_close(IOStream *s){
return fclose(get_file(s));
}
/** Free a file stream.
*
* @param s file stream
*/
static void file_free(IOStream *s){
// Do nothing - fclose does it all?
}
/** Create an IOStream for a stream.
*
* @param f stream to wrap
* @return new IOStream using f for i/o
*/
IOStream *file_stream_new(FILE *f){
IOStream *io = ALLOCATE(IOStream);
if(io){
io->methods = &file_methods;
io->data = (void*)f;
}
return io;
}
/** IOStream version of fopen().
*
* @param file name of the file to open
* @param flags giving the mode to open in (as for fopen())
* @return new stream for the open file, or 0 if failed
*/
IOStream *file_stream_fopen(const char *file, const char *flags){
IOStream *io = 0;
FILE *fin = fopen(file, flags);
if(fin){
io = file_stream_new(fin);
if(!io){
fclose(fin);
//free(fin); // fclose frees ?
}
}
return io;
}
/** IOStream version of fdopen().
*
* @param fd file descriptor
* @param flags giving the mode to open in (as for fdopen())
* @return new stream for the open file, or 0 if failed
*/
IOStream *file_stream_fdopen(int fd, const char *flags){
IOStream *io = 0;
FILE *fin = fdopen(fd, flags);
if(fin){
io = file_stream_new(fin);
}
return io;
}
#endif
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_FILE_STREAM_H_
#define _XEN_LIB_FILE_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
#include <stdio.h>
extern IOStream *file_stream_new(FILE *f);
extern IOStream *file_stream_fopen(const char *file, const char *flags);
extern IOStream *file_stream_fdopen(int fd, const char *flags);
extern IOStream get_stream_stdout(void);
extern IOStream get_stream_stderr(void);
extern IOStream get_stream_stdin(void);
extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
#endif
#endif /* !_XEN_LIB_FILE_STREAM_H_ */
+171
View File
@@ -0,0 +1,171 @@
/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using zlib gzFile to provide
* compression and decompression.
*/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include "zlib.h"
#include "allocate.h"
#include "gzip_stream.h"
static int gzip_read(IOStream *s, void *buf, size_t n);
static int gzip_write(IOStream *s, const void *buf, size_t n);
static int gzip_error(IOStream *s);
static int gzip_close(IOStream *s);
static void gzip_free(IOStream *s);
static int gzip_flush(IOStream *s);
/** Methods used by a gzFile* IOStream. */
static const IOMethods gzip_methods = {
read: gzip_read,
write: gzip_write,
error: gzip_error,
close: gzip_close,
free: gzip_free,
flush: gzip_flush,
};
/** Get the underlying gzFile*.
*
* @param s gzip stream
* @return the stream s wraps
*/
static inline gzFile get_gzfile(IOStream *s){
return (gzFile)s->data;
}
/** Write to the underlying stream.
*
* @param stream destination
* @param buf data
* @param n number of bytes to write
* @return number of bytes written
*/
static int gzip_write(IOStream *s, const void *buf, size_t n){
return gzwrite(get_gzfile(s), (void*)buf, n);
}
/** Read from the underlying stream.
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to read
* @return number of bytes read
*/
static int gzip_read(IOStream *s, void *buf, size_t n){
return gzread(get_gzfile(s), buf, n);
}
/** Flush the underlying stream.
*
* @param s gzip stream
* @return 0 on success, error code otherwise
*/
static int gzip_flush(IOStream *s){
//return gzflush(get_gzfile(s), Z_NO_FLUSH);
return gzflush(get_gzfile(s), Z_SYNC_FLUSH);
//return gzflush(get_gzfile(s), Z_FULL_FLUSH);
}
/** Check if a stream has an error.
*
* @param s gzip stream
* @return 1 if has an error, 0 otherwise
*/
static int gzip_error(IOStream *s){
int err;
gzFile *gz = get_gzfile(s);
gzerror(gz, &err);
return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err);
}
/** Close a gzip stream.
*
* @param s gzip stream to close
* @return result of the close
*/
static int gzip_close(IOStream *s){
return gzclose(get_gzfile(s));
}
/** Free a gzip stream.
*
* @param s gzip stream
*/
static void gzip_free(IOStream *s){
// Do nothing - fclose does it all?
}
/** Create an IOStream for a gzip stream.
*
* @param f stream to wrap
* @return new IOStream using f for i/o
*/
IOStream *gzip_stream_new(gzFile *f){
IOStream *io = ALLOCATE(IOStream);
if(io){
io->methods = &gzip_methods;
io->data = (void*)f;
}
return io;
}
/** IOStream version of fopen().
*
* @param file name of the file to open
* @param flags giving the mode to open in (as for fopen())
* @return new stream for the open file, or NULL if failed
*/
IOStream *gzip_stream_fopen(const char *file, const char *flags){
IOStream *io = NULL;
gzFile *fgz;
fgz = gzopen(file, flags);
if(fgz){
io = gzip_stream_new(fgz);
if(!io){
gzclose(fgz);
//free(fgz); // gzclose frees ?
}
}
return io;
}
/** IOStream version of fdopen().
*
* @param fd file descriptor
* @param flags giving the mode to open in (as for fdopen())
* @return new stream for the open file, or NULL if failed
*/
IOStream *gzip_stream_fdopen(int fd, const char *flags){
IOStream *io = NULL;
gzFile *fgz;
fgz = gzdopen(fd, flags);
if(fgz){
io = gzip_stream_new(fgz);
}
return io;
}
#endif
+31
View File
@@ -0,0 +1,31 @@
#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_GZIP_STREAM_H_
#define _SP_GZIP_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
#include "zlib.h"
extern IOStream *gzip_stream_new(gzFile *f);
extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
#endif
#endif /* !_SP_FILE_STREAM_H_ */
+640
View File
@@ -0,0 +1,640 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __KERNEL__
# include <linux/config.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
#else
# include <errno.h>
# include <stddef.h>
#endif
//#include <limits.h>
#include "allocate.h"
#include "hash_table.h"
/** @file
* Base support for hashtables.
*
* Hash codes are reduced modulo the number of buckets to index tables,
* so there is no need for hash functions to limit the range of hashcodes.
* In fact it is assumed that hashcodes do not change when the number of
* buckets in the table changes.
*/
/*==========================================================================*/
/** Number of bits in half a word. */
//#if __WORDSIZE == 64
//#define HALF_WORD_BITS 32
//#else
#define HALF_WORD_BITS 16
//#endif
/** Mask for lo half of a word. On 32-bit this is
* (1<<16) - 1 = 65535 = 0xffff
* It's 4294967295 = 0xffffffff on 64-bit.
*/
#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
/** Get the lo half of a word. */
#define LO_HALF(x) ((x) & LO_HALF_MASK)
/** Get the hi half of a word. */
#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
/** Do a full hash on both inputs, using DES-style non-linear scrambling.
* Both inputs are replaced with the results of the hash.
*
* @param pleft input/output word
* @param pright input/output word
*/
void pseudo_des(unsigned long *pleft, unsigned long *pright){
// Bit-rich mixing constant.
static const unsigned long a_mixer[] = {
0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
// Bit-rich mixing constant.
static const unsigned long b_mixer[] = {
0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
// Number of iterations - must be 2 or 4.
static const int ncycle = 4;
//static const int ncycle = 2;
unsigned long left = *pleft, right = *pright;
unsigned long v, v_hi, v_lo;
int i;
for(i=0; i<ncycle; i++){
// Flip some bits in right to get v.
v = right;
v ^= a_mixer[i];
// Get lo and hi halves of v.
v_lo = LO_HALF(v);
v_hi = HI_HALF(v);
// Non-linear mix of the halves of v.
v = ((v_lo * v_lo) + ~(v_hi * v_hi));
// Swap the halves of v.
v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
// Flip some bits.
v ^= b_mixer[i];
// More non-linear mixing.
v += (v_lo * v_hi);
v ^= left;
left = right;
right = v;
}
*pleft = left;
*pright = right;
}
/** Hash a string.
*
* @param s input to hash
* @return hashcode
*/
Hashcode hash_string(char *s){
Hashcode h = 0;
if(s){
for( ; *s; s++){
h = hash_2ul(h, *s);
}
}
return h;
}
/** Get the bucket for a hashcode in a hash table.
*
* @param table to get bucket from
* @param hashcode to get bucket for
* @return bucket
*/
inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
return table->buckets + (hashcode % table->buckets_n);
}
/** Initialize a hash table.
* Can be safely called more than once.
*
* @param table to initialize
*/
void HashTable_init(HashTable *table){
int i;
if(!table->init_done){
table->init_done = 1;
table->next_id = 0;
for(i=0; i<table->buckets_n; i++){
HTBucket *bucket = get_bucket(table, i);
bucket->head = 0;
bucket->count = 0;
}
table->entry_count = 0;
}
}
/** Allocate a new hashtable.
* If the number of buckets is not positive the default is used.
* The number of buckets should usually be prime.
*
* @param buckets_n number of buckets
* @return new hashtable or null
*/
HashTable *HashTable_new(int buckets_n){
HashTable *z = ALLOCATE(HashTable);
if(!z) goto exit;
if(buckets_n <= 0){
buckets_n = HT_BUCKETS_N;
}
z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
if(!z->buckets){
deallocate(z);
z = 0;
goto exit;
}
z->buckets_n = buckets_n;
HashTable_init(z);
exit:
return z;
}
/** Free a hashtable.
* Any entries are removed and freed.
*
* @param h hashtable (ignored if null)
*/
void HashTable_free(HashTable *h){
if(h){
HashTable_clear(h);
deallocate(h->buckets);
deallocate(h);
}
}
/** Push an entry on the list in the bucket for a given hashcode.
*
* @param table to add entry to
* @param hashcode for the entry
* @param entry to add
*/
static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
HTEntry *entry){
HTBucket *bucket;
HTEntry *old_head;
bucket = get_bucket(table, hashcode);
old_head = bucket->head;
bucket->count++;
bucket->head = entry;
entry->next = old_head;
}
/** Change the number of buckets in a hashtable.
* No-op if the number of buckets is not positive.
* Existing entries are reallocated to buckets based on their hashcodes.
* The table is unmodified if the number of buckets cannot be changed.
*
* @param table hashtable
* @param buckets_n new number of buckets
* @return 0 on success, error code otherwise
*/
int HashTable_set_buckets_n(HashTable *table, int buckets_n){
int err = 0;
HTBucket *old_buckets = table->buckets;
int old_buckets_n = table->buckets_n;
int i;
if(buckets_n <= 0){
err = -EINVAL;
goto exit;
}
table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
if(!table->buckets){
err = -ENOMEM;
table->buckets = old_buckets;
goto exit;
}
table->buckets_n = buckets_n;
for(i=0; i<old_buckets_n; i++){
HTBucket *bucket = old_buckets + i;
HTEntry *entry, *next;
for(entry = bucket->head; entry; entry = next){
next = entry->next;
push_on_bucket(table, entry->hashcode, entry);
}
}
deallocate(old_buckets);
exit:
return err;
}
/** Adjust the number of buckets so the table is neither too full nor too empty.
* The table is unmodified if adjusting fails.
*
* @param table hash table
* @param buckets_min minimum number of buckets (use default if 0 or negative)
* @return 0 on success, error code otherwise
*/
int HashTable_adjust(HashTable *table, int buckets_min){
int buckets_n = 0;
int err = 0;
if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
if(table->entry_count >= table->buckets_n){
// The table is dense - expand it.
buckets_n = 2 * table->buckets_n;
} else if((table->buckets_n > buckets_min) &&
(4 * table->entry_count < table->buckets_n)){
// The table is more than minimum size and sparse - shrink it.
buckets_n = 2 * table->entry_count;
if(buckets_n < buckets_min) buckets_n = buckets_min;
}
if(buckets_n){
err = HashTable_set_buckets_n(table, buckets_n);
}
return err;
}
/** Allocate a new entry for a given value.
*
* @param value to put in the entry
* @return entry, or 0 on failure
*/
HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
HTEntry *z = ALLOCATE(HTEntry);
if(z){
z->hashcode = hashcode;
z->key = key;
z->value = value;
}
return z;
}
/** Free an entry.
*
* @param z entry to free
*/
inline void HTEntry_free(HTEntry *z){
if(z){
deallocate(z);
}
}
/** Free an entry in a hashtable.
* The table's entry_free_fn is used is defined, otherwise
* the HTEntry itself is freed.
*
* @param table hashtable
* @param entry to free
*/
inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
if(!entry)return;
if(table && table->entry_free_fn){
table->entry_free_fn(table, entry);
} else {
HTEntry_free(entry);
}
}
/** Get the first entry satisfying a test from the bucket for the
* given hashcode.
*
* @param table to look in
* @param hashcode indicates the bucket
* @param test_fn test to apply to elements
* @param arg first argument to calls to test_fn
* @return entry found, or 0
*/
inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg){
HTBucket *bucket;
HTEntry *entry = 0;
HTEntry *next;
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(test_fn(arg, table, entry)){
break;
}
}
return entry;
}
/** Test hashtable keys for equality.
* Uses the table's key_equal_fn if defined, otherwise pointer equality.
*
* @param key1 key to compare
* @param key2 key to compare
* @return 1 if equal, 0 otherwise
*/
inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
}
/** Compute the hashcode of a hashtable key.
* The table's key_hash_fn is used if defined, otherwise the address of
* the key is hashed.
*
* @param table hashtable
* @param key to hash
* @return hashcode
*/
inline Hashcode HashTable_key_hash(HashTable *table, void *key){
return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
}
/** Test if an entry has a given key.
*
* @param arg containing key to test for
* @param table the entry is in
* @param entry to test
* @return 1 if the entry has the key, 0 otherwise
*/
static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
return HashTable_key_equal(table, arg.ptr, entry->key);
}
/** Get an entry with a given key.
*
* @param table to search
* @param key to look for
* @return entry if found, null otherwise
*/
#if 0
inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
TableArg arg = { ptr: key };
return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
}
#else
inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
Hashcode hashcode;
HTBucket *bucket;
HTEntry *entry = 0;
HTEntry *next;
hashcode = HashTable_key_hash(table, key);
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(HashTable_key_equal(table, key, entry->key)){
break;
}
}
return entry;
}
#endif
/** Get the value of an entry with a given key.
*
* @param table to search
* @param key to look for
* @return value if an entry was found, null otherwise
*/
inline void * HashTable_get(HashTable *table, void *key){
HTEntry *entry = HashTable_get_entry(table, key);
return (entry ? entry->value : 0);
}
/** Print the buckets in a table.
*
* @param table to print
*/
void show_buckets(HashTable *table, IOStream *io){
int i,j ;
IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
for(i=0; i<table->buckets_n; i++){
if(0 || table->buckets[i].count>0){
IOStream_print(io, "bucket %3d %3d %10p ", i,
table->buckets[i].count,
table->buckets[i].head);
for(j = table->buckets[i].count; j>0; j--){
IOStream_print(io, "+");
}
IOStream_print(io, "\n");
}
}
HashTable_print(table, io);
}
/** Print an entry in a table.
*
* @param entry to print
* @param arg a pointer to an IOStream to print to
* @return 0
*/
static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
IOStream *io = (IOStream*)arg.ptr;
IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
entry->hashcode % table->buckets_n,
entry->hashcode,
entry->index,
entry, entry->key, entry->value);
return 0;
}
/** Print a hash table.
*
* @param table to print
*/
void HashTable_print(HashTable *table, IOStream *io){
IOStream_print(io, "{\n");
HashTable_map(table, print_entry, (TableArg){ ptr: io });
IOStream_print(io, "}\n");
}
/*==========================================================================*/
/** Get the next entry id to use for a table.
*
* @param table hash table
* @return non-zero entry id
*/
static inline unsigned long get_next_id(HashTable *table){
unsigned long id;
if(table->next_id == 0){
table->next_id = 1;
}
id = table->next_id++;
return id;
}
/** Add an entry to the bucket for the
* given hashcode.
*
* @param table to insert in
* @param hashcode indicates the bucket
* @param key to add an entry for
* @param value to add an entry for
* @return entry on success, 0 on failure
*/
inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
HTEntry *entry = HTEntry_new(hashcode, key, value);
if(entry){
entry->index = get_next_id(table);
push_on_bucket(table, hashcode, entry);
table->entry_count++;
}
return entry;
}
/** Move the front entry for a bucket to the correct point in the bucket order as
* defined by the order function. If this is called every time a new entry is added
* the bucket will be maintained in sorted order.
*
* @param table to modify
* @param hashcode indicates the bucket
* @param order entry comparison function
* @return 0 if an entry was moved, 1 if not
*/
int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
HTBucket *bucket;
int err = 1;
bucket = get_bucket(table, hashcode);
new_entry = bucket->head;
if(!new_entry || !new_entry->next) goto exit;
for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
if(order(new_entry, entry) <= 0) break;
}
if(prev){
err = 0;
bucket->head = new_entry->next;
new_entry->next = entry;
prev->next = new_entry;
}
exit:
return err;
}
/** Add an entry to a hashtable.
* The entry is added to the bucket for its key's hashcode.
*
* @param table to insert in
* @param key to add an entry for
* @param value to add an entry for
* @return entry on success, 0 on failure
*/
inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
}
/** Remove entries satisfying a test from the bucket for the
* given hashcode.
*
* @param table to remove from
* @param hashcode indicates the bucket
* @param test_fn test to apply to elements
* @param arg first argument to calls to test_fn
* @return number of entries removed
*/
inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg){
HTBucket *bucket;
HTEntry *entry, *prev = 0, *next;
int removed_count = 0;
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(test_fn(arg, table, entry)){
if(prev){
prev->next = next;
} else {
bucket->head = next;
}
bucket->count--;
table->entry_count--;
removed_count++;
HashTable_free_entry(table, entry);
entry = 0;
}
prev = entry;
}
return removed_count;
}
/** Remove entries with a given key.
*
* @param table to remove from
* @param key of entries to remove
* @return number of entries removed
*/
inline int HashTable_remove(HashTable *table, void *key){
#if 1
Hashcode hashcode;
HTBucket *bucket;
HTEntry *entry, *prev = 0, *next;
int removed_count = 0;
hashcode = HashTable_key_hash(table, key);
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(HashTable_key_equal(table, key, entry->key)){
if(prev){
prev->next = next;
} else {
bucket->head = next;
}
bucket->count--;
table->entry_count--;
removed_count++;
HashTable_free_entry(table, entry);
entry = 0;
}
prev = entry;
}
return removed_count;
#else
return HashTable_remove_entry(table, HashTable_key_hash(table, key),
has_key, (TableArg){ ptr: key});
#endif
}
/** Remove (and free) all the entries in a bucket.
*
* @param bucket to clear
*/
static inline void bucket_clear(HashTable *table, HTBucket *bucket){
HTEntry *entry, *next;
for(entry = bucket->head; entry; entry = next){
next = entry->next;
HashTable_free_entry(table, entry);
}
bucket->head = 0;
table->entry_count -= bucket->count;
bucket->count = 0;
}
/** Remove (and free) all the entries in a table.
*
* @param table to clear
*/
void HashTable_clear(HashTable *table){
int i, n = table->buckets_n;
for(i=0; i<n; i++){
bucket_clear(table, table->buckets + i);
}
}
+295
View File
@@ -0,0 +1,295 @@
/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_HASH_TABLE_H_
#define _XEN_LIB_HASH_TABLE_H_
#include "iostream.h"
typedef unsigned long Hashcode;
/** Type used to pass parameters to table functions. */
typedef union TableArg {
unsigned long ul;
void *ptr;
} TableArg;
/** An entry in a bucket list. */
typedef struct HTEntry {
/** Hashcode of the entry's key. */
Hashcode hashcode;
/** Identifier for this entry in the table. */
int index;
/** The key for this entry. */
void *key;
/** The value in this entry. */
void *value;
/** The next entry in the list. */
struct HTEntry *next;
} HTEntry;
/** A bucket in a rule table. */
typedef struct HTBucket {
/** Number of entries in the bucket. */
int count;
/** First entry in the bucket (may be null). */
HTEntry *head;
} HTBucket;
/** Default number of buckets in a hash table.
* You want enough buckets so the lists in the buckets will typically be short.
* It's a good idea if this is prime, since that will help to spread hashcodes
* around the table.
*/
//#define HT_BUCKETS_N 1
//#define HT_BUCKETS_N 3
//#define HT_BUCKETS_N 7
//#define HT_BUCKETS_N 17
//#define HT_BUCKETS_N 97
//#define HT_BUCKETS_N 211
//#define HT_BUCKETS_N 401
#define HT_BUCKETS_N 1021
typedef struct HashTable HashTable;
/** Type for a function used to select table entries. */
typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
/** Type for a function to map over table entries. */
typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
/** Type for a function to free table entries. */
typedef void TableFreeFn(HashTable *table, HTEntry *entry);
/** Type for a function to hash table keys. */
typedef Hashcode TableHashFn(void *key);
/** Type for a function to test table keys for equality. */
typedef int TableEqualFn(void *key1, void *key2);
/** Type for a function to order table entries. */
typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
/** General hash table.
* A hash table with a list in each bucket.
* Functions can be supplied for freeing entries, hashing keys, and comparing keys.
* These all default to 0, when default behaviour treating keys as integers is used.
*/
struct HashTable {
/** Flag indicating whether the table has been initialised. */
int init_done;
/** Next value for the id field in inserted rules. */
unsigned long next_id;
/** Number of buckets in the bucket array. */
int buckets_n;
/** Array of buckets, each with its own list. */
HTBucket *buckets;
/** Number of entries in the table. */
int entry_count;
/** Function to free keys and values in entries. */
TableFreeFn *entry_free_fn;
/** Function to hash keys. */
TableHashFn *key_hash_fn;
/** Function to compare keys for equality. */
TableEqualFn *key_equal_fn;
/** Place for the user of the table to hang extra data. */
void *user_data;
};
extern HashTable *HashTable_new(int bucket_n);
extern void HashTable_free(HashTable *table);
extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
extern void HTEntry_free(HTEntry *entry);
extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
extern void HashTable_clear(HashTable *table);
extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
extern void * HashTable_get(HashTable *table, void *key);
extern int HashTable_remove(HashTable *table, void *key);
extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg);
extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg);
//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
extern void HashTable_print(HashTable *table, IOStream *out);
extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
extern int HashTable_adjust(HashTable *table, int buckets_min);
extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
extern Hashcode hash_string(char *s);
extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
/** Control whether to use hashing based on DES or simple
* hashing. DES hashing is `more random' but much more expensive.
*/
#define HASH_PSEUDO_DES 0
/** Hash a long using a quick and dirty linear congruential random number generator.
* See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
*
* @param a value to hash
* @return hashed input
*/
static inline unsigned long lcrng_hash(unsigned long a){
return (1664525L * a + 1013904223L);
}
/** Hash an unsigned long.
*
* @param a input to hash
* @return hashcode
*/
static inline Hashcode hash_ul(unsigned long a){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = 0L;
pseudo_des(&left, &right);
return right;
#else
a = lcrng_hash(a);
a = lcrng_hash(a);
return a;
#endif
}
/** Hash two unsigned longs together.
*
* @param a input to hash
* @param b input to hash
* @return hashcode
*/
static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = b;
pseudo_des(&left, &right);
return right;
#else
a = lcrng_hash(a);
a ^= b;
a = lcrng_hash(a);
return a;
#endif
}
/** Hash a hashcode and an unsigned long together.
*
* @param a input hashcode
* @param b input to hash
* @return hashcode
*/
static inline Hashcode hash_hul(Hashcode a, unsigned long b){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = b;
pseudo_des(&left, &right);
return right;
#else
a ^= b;
a = lcrng_hash(a);
return a;
#endif
}
/** Macro to declare variables for HashTable_for_each() to use.
*
* @param entry variable that is set to entries in the table
*/
#define HashTable_for_decl(entry) \
HashTable *_var_table; \
HTBucket *_var_bucket; \
HTBucket *_var_end; \
HTEntry *_var_next; \
HTEntry *entry
/** Macro to iterate over the entries in a hashtable.
* Must be in a scope where HashTable_for_decl() has been used to declare
* variables for it to use.
* The variable 'entry' is iterated over entries in the table.
* The code produced is syntactically a loop, so it must be followed by
* a loop body, typically some statements in braces:
* HashTable_for_each(entry, table){ ...loop body... }
*
* HashTable_for_each() and HashTable_for_decl() cannot be used for nested
* loops as variables will clash.
*
* @note The simplest way to code a direct loop over the entries in a hashtable
* is to use a loop over the buckets, with a nested loop over the entries
* in a bucket. Using this approach in a macro means the macro contains
* an opening brace, and calls to it must be followed by 2 braces!
* To avoid this the code has been restructured so that it is a for loop.
* So that statements could be used in the test expression of the for loop,
* we have used the gcc statement expression extension ({ ... }).
*
* @param entry variable to iterate over the entries
* @param table to iterate over (non-null)
*/
#define HashTable_for_each(entry, table) \
_var_table = table; \
_var_bucket = _var_table->buckets; \
_var_end = _var_bucket + _var_table->buckets_n; \
for(entry=0, _var_next=0; \
({ if(_var_next){ \
entry = _var_next; \
_var_next = entry->next; \
} else { \
while(_var_bucket < _var_end){ \
entry = _var_bucket->head; \
_var_bucket++; \
if(entry){ \
_var_next = entry->next; \
break; \
} \
} \
}; \
entry; }); \
entry = _var_next )
/** Map a function over the entries in a table.
* Mapping stops when the function returns a non-zero value.
* Uses the gcc statement expression extension ({ ... }).
*
* @param table to map over
* @param fn function to apply to entries
* @param arg first argument to call the function with
* @return 0 if fn always returned 0, first non-zero value otherwise
*/
#define HashTable_map(table, fn, arg) \
({ HashTable_for_decl(_var_entry); \
TableArg _var_arg = arg; \
int _var_value = 0; \
HashTable_for_each(_var_entry, table){ \
if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
} \
_var_value; })
/** Cast x to the type for a key or value in a hash table.
* This avoids compiler warnings when using short integers
* as keys or values (especially on 64-bit platforms).
*/
#define HKEY(x) ((void*)(unsigned long)(x))
/** Cast x from the type for a key or value in a hash table.
* to an unsigned long. This avoids compiler warnings when using
* short integers as keys or values (especially on 64-bit platforms).
*/
#define HVAL(x) ((unsigned long)(x))
#endif /* !_XEN_LIB_HASH_TABLE_H_ */
+37
View File
@@ -0,0 +1,37 @@
#include "iostream.h"
#include "sys_string.h"
/** Print on a stream, like vfprintf().
*
* @param stream to print to
* @param format for the print (as fprintf())
* @param args arguments to print
* @return result code from the print
*/
int IOStream_vprint(IOStream *stream, const char *format, va_list args){
char buffer[1024];
int k = sizeof(buffer), n;
n = vsnprintf(buffer, k, (char*)format, args);
if(n < 0 || n > k ){
n = k;
}
n = IOStream_write(stream, buffer, n);
return n;
}
/** Print on a stream, like fprintf().
*
* @param stream to print to
* @param format for the print (as fprintf())
* @return result code from the print
*/
int IOStream_print(IOStream *stream, const char *format, ...){
va_list args;
int result = -1;
va_start(args, format);
result = IOStream_vprint(stream, format, args);
va_end(args);
return result;
}
+243
View File
@@ -0,0 +1,243 @@
#ifndef _XC_LINUX_SAVE_H_
#define _XC_LINUX_SAVE_H_
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __KERNEL__
#include <linux/errno.h>
#else
#include <errno.h>
#endif
#include "allocate.h"
/** End of input return value. */
#define IOSTREAM_EOF -1
/** An input/output abstraction.
*/
typedef struct IOStream IOStream;
/** Record of the functions to use for operations on an
* IOStream implementation.
*/
typedef struct IOMethods {
/** Read function. Called with the user data, buffer to read into
* and number of bytes to read. Must return number of bytes read
* on success, less than zero on error.
*/
int (*read)(IOStream *stream, void *buf, size_t n);
/** Write function. Called with user data, buffer to write and
* number of bytes to write. Must return number of bytes written on
* success, less than zero otherwise.
*/
int (*write)(IOStream *stream, const void *buf, size_t n);
int (*flush)(IOStream *s);
int (*error)(IOStream *s);
int (*close)(IOStream *s);
void (*free)(IOStream *s);
void (*lock)(IOStream *s);
void (*unlock)(IOStream *s);
} IOMethods;
/** Abstract i/o object.
*/
struct IOStream {
/** Methods to use to implement operations. */
const IOMethods *methods;
/** Private state for the implementation. */
const void *data;
/** Flag indicating whether the stream is closed. */
int closed;
/** Number of bytes written. */
int written;
/** Number of bytes read. */
int read;
};
/** IOStream version of stdin. */
extern IOStream *iostdin;
/** IOStream version of stdout, */
extern IOStream *iostdout;
/** IOStream version of stderr. */
extern IOStream *iostderr;
extern int IOStream_print(IOStream *io, const char *format, ...);
extern int IOStream_vprint(IOStream *io, const char *format, va_list args);
/** Read from a stream.
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to read
* @return if ok, number of bytes read, otherwise negative error code
*/
static inline int IOStream_read(IOStream *stream, void *buf, size_t n){
int result = 0;
if(stream->closed) goto exit;
if(!stream->methods || !stream->methods->read){
result = -EINVAL;
goto exit;
}
result = stream->methods->read(stream, buf, n);
if(result > 0){
stream->read += result;
}
exit:
return result;
}
/** Write to a stream.
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to write
* @return if ok, number of bytes read, otherwise negative error code
*/
static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){
int result = 0;
if(stream->closed) goto exit;
if(!stream->methods || !stream->methods->write){
result = -EINVAL;
goto exit;
}
result = stream->methods->write(stream, buf, n);
if(result > 0){
stream->written += result;
}
exit:
return result;
}
/** Flush the stream.
*
* @param stream stream
* @return 0 on success, IOSTREAM_EOF otherwise
*/
static inline int IOStream_flush(IOStream *stream){
int result = 0;
if(stream->closed){
result = IOSTREAM_EOF;
} else if(stream->methods->flush){
result = stream->methods->flush(stream);
if(result < 0) result = IOSTREAM_EOF;
}
return result;
}
/** Check whether the stream has an error.
*
* @param stream to check
* @return 1 for error, 0 otherwise
*/
static inline int IOStream_error(IOStream *stream){
int err = 0;
if(stream->methods && stream->methods->error){
err = stream->methods->error(stream);
}
return err;
}
/** Close the stream.
*
* @param stream to close
* @return 1 for error, 0 otherwise
*/
static inline int IOStream_close(IOStream *stream){
int err = 1;
if(stream->methods && stream->methods->close){
err = stream->methods->close(stream);
}
return err;
}
/** Test if the stream has been closed.
*
* @param stream to check
* @return 1 if closed, 0 otherwise
*/
static inline int IOStream_is_closed(IOStream *stream){
return stream->closed;
}
/** Free the memory used by the stream.
*
* @param stream to free
*/
static inline void IOStream_free(IOStream *stream){
if(stream->methods && stream->methods->free){
stream->methods->free(stream);
}
*stream = (IOStream){};
deallocate(stream);
}
/** Print a character to a stream, like fputc().
*
* @param stream to print to
* @param c character to print
* @return result code from the print
*/
static inline int IOStream_putc(IOStream *stream, int c){
int err;
unsigned char b = (unsigned char)c;
err = IOStream_write(stream, &b, 1);
if(err < 1){
err = IOSTREAM_EOF;
} else {
err = b;
}
return err;
}
/** Read from a stream, like fgetc().
*
* @param stream to read from
* @return IOSTREAM_EOF on error, character read otherwise
*/
static inline int IOStream_getc(IOStream *stream){
int err, rc;
unsigned char b;
err = IOStream_read(stream, &b, 1);
if(err < 1){
rc = IOSTREAM_EOF;
} else {
rc = b;
}
return rc;
}
/** Get number of bytes read.
*
* @param stream to get from
* @return number of bytes read
*/
static inline int IOStream_get_read(IOStream *stream){
return stream->read;
}
/** Get number of bytes written.
*
* @param stream to get from
* @return number of bytes written
*/
static inline int IOStream_get_written(IOStream *stream){
return stream->written;
}
#endif /* ! _XC_LINUX_SAVE_H_ */
+177
View File
@@ -0,0 +1,177 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using printk() for output.
* Input is not implemented.
*/
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "kernel_stream.h"
#include "allocate.h"
/** Number of characters in the output buffer.
* The kernel uses 1024 for printk, so that should suffice.
*/
#define BUF_N 1024
/** State for a kernel stream. */
typedef struct KernelData {
/** Stream lock. We need a lock to serialize access to the stream. */
spinlock_t lock;
/** Saved flags for locking. */
unsigned long flags;
/** Size of the output buffer. */
int buf_n;
/** Output buffer. */
char buf[BUF_N];
} KernelData;
static int kernel_write(IOStream *s, const char *msg, int n);
static void kernel_free(IOStream *s);
static void kernel_stream_lock(IOStream *s);
static void kernel_stream_unlock(IOStream *s);
/** Methods for a kernel stream. Output only. */
static const IOMethods kernel_methods = {
write: kernel_write,
free: kernel_free,
lock: kernel_stream_lock,
unlock: kernel_stream_unlock,
};
/** Shared state for kernel streams.
* All implementations write using printk, so we can use
* shared state and avoid allocating it.
*/
static const KernelData kernel_data = {
lock: SPIN_LOCK_UNLOCKED,
flags: 0,
buf_n: BUF_N,
};
/** Stream for kernel printk. */
static IOStream iokernel = {
methods: &kernel_methods,
data: &kernel_data,
};
/** Stream for kernel printk. */
IOStream *iostdout = &iokernel;
/** Stream for kernel printk. */
IOStream *iostdin = &iokernel;
/** Stream for kernel printk. */
IOStream *iostderr = &iokernel;
/** Get an output-only stream implementation using
* printk(). The stream uses static storage, and must not be freed.
*
* @return kernel stream
*/
IOStream get_stream_kernel(void){
return iokernel;
}
/** Obtain the lock on the stream state.
*
* @param kdata stream state
*/
static inline void KernelData_lock(KernelData *kdata){
spin_lock_irqsave(&kdata->lock, kdata->flags);
}
/** Release the lock on the stream state.
*
* @param kdata stream state
*/
static inline void KernelData_unlock(KernelData *kdata){
spin_unlock_irqrestore(&kdata->lock, kdata->flags);
}
/** Get the stream state.
*
* @param s kernel stream
* @return stream state
*/
static inline KernelData *get_kernel_data(IOStream *s){
return (KernelData*)s->data;
}
/** Obtain the lock on the stream state.
*
* @param s stream
*/
void kernel_stream_lock(IOStream *s){
KernelData_lock(get_kernel_data(s));
}
/** Release the lock on the stream state.
*
* @param s stream
*/
void kernel_stream_unlock(IOStream *s){
KernelData_unlock(get_kernel_data(s));
}
/** Write to a kernel stream.
*
* @param stream kernel stream
* @param format print format
* @param args print arguments
* @return result of the print
*/
static int kernel_write(IOStream *stream, const char *buf, int n){
KernelData *kdata = get_kernel_data(stream);
int k;
k = kdata->buf_n - 1;
if(n < k) k = n;
memcpy(kdata->buf, buf, k);
kdata->buf[k] = '\0'
printk(kdata->buf);
return k;
}
/** Free a kernel stream.
* Frees the internal state of the stream.
* Do not call this unless the stream was dynamically allocated.
* Do not call this on a stream returned from get_stream_kernel().
*
* @param io stream to free
*/
static void kernel_free(IOStream *io){
KernelData *kdata;
if(io == &iokernel) return;
kdata = get_kernel_data(io);
zero(kdata, sizeof(*kdata));
deallocate(kdata);
}
#endif /* __KERNEL__ */
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_KERNEL_STREAM_H_
#define _XEN_LIB_KERNEL_STREAM_H_
#ifdef __KERNEL__
#include "iostream.h"
extern IOStream get_stream_kernel(void);
#define get_stream_stdout get_stream_kernel
#endif /* __KERNEL__ */
#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
+93
View File
@@ -0,0 +1,93 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* Lexical analysis.
*/
#include "sys_string.h"
#include "lexis.h"
#include <errno.h>
/** Check if a value lies in a (closed) range.
*
* @param x value to test
* @param lo low end of the range
* @param hi high end of the range
* @return 1 if x is in the interval [lo, hi], 0 otherwise
*/
inline static int in_range(int x, int lo, int hi){
return (lo <= x) && (x <= hi);
}
/** Determine if a string is an (unsigned) decimal number.
*
* @param s pointer to characters to test
* @param n length of string
* @return 1 if s is a decimal number, 0 otherwise.
*/
int is_decimal_number(const char *s, int n){
int i;
if(n <= 0)return 0;
for(i = 0; i < n; i++){
if(!in_decimal_digit_class(s[i])) return 0;
}
return 1;
}
/** Determine if a string is a hex number.
* Hex numbers are 0, or start with 0x or 0X followed
* by a non-zero number of hex digits (0-9,a-f,A-F).
*
* @param s pointer to characters to test
* @param n length of string
* @return 1 if s is a hex number, 0 otherwise.
*/
int is_hex_number(const char *s, int n){
int i;
if(n <= 0) return 0;
if(n == 1){
return s[0]=='0';
}
if(n <= 3) return 0;
if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
for(i = 2; i < n; i++){
if(!in_hex_digit_class(s[i])) return 0;
}
return 1;
}
/** Test if a string matches a keyword.
* The comparison is case-insensitive.
* The comparison fails if either argument is null.
*
* @param s string
* @param k keyword
* @return 1 if they match, 0 otherwise
*/
int is_keyword(const char *s, const char *k){
return s && k && !strcasecmp(s, k);
}
/** Test if a string matches a character.
*
* @param s string
* @param c character (non-null)
* @return 1 if s contains exactly c, 0 otherwise
*/
int is_keychar(const char *s, char c){
return c && (s[0] == c) && !s[1];
}
+122
View File
@@ -0,0 +1,122 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_LEXIS_H_
#define _SP_LEXIS_H_
#include "sys_string.h"
#include "sys_ctype.h"
/** @file
* Lexical analysis.
*/
/** Class of characters treated as space. */
#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
/** Class of separator characters. */
#define sep_class "{}()<>[]@!;"
#define comment_class "#"
/** Determine if a character is in a given class.
*
* @param c character to test
* @param s null-terminated string of characters in the class
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_class(int c, const char *s){
return s && (strchr(s, c) != 0);
}
/** Determine if a character is in the space class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_space_class(int c){
return in_class(c, space_class);
}
static inline int in_comment_class(int c){
return in_class(c, comment_class);
}
/** Determine if a character is in the separator class.
* Separator characters terminate tokens, and do not need space
* to separate them.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_sep_class(int c){
return in_class(c, sep_class);
}
/** Determine if a character is in the alpha class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_alpha_class(int c){
return isalpha(c);
}
/** Determine if a character is in the octal digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_octal_digit_class(int c){
return '0' <= c && c <= '7';
}
/** Determine if a character is in the decimal digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_decimal_digit_class(int c){
return isdigit(c);
}
/** Determine if a character is in the hex digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_hex_digit_class(int c){
return isdigit(c) || in_class(c, "abcdefABCDEF");
}
static inline int in_string_quote_class(int c){
return in_class(c, "'\"");
}
static inline int in_printable_class(int c){
return ('A' <= c && c <= 'Z')
|| ('a' <= c && c <= 'z')
|| ('0' <= c && c <= '9')
|| in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
}
extern int is_decimal_number(const char *s, int n);
extern int is_hex_number(const char *s, int n);
extern int is_keyword(const char *s, const char *k);
extern int is_keychar(const char *s, char c);
#endif /* !_SP_LEXIS_H_ */
+590
View File
@@ -0,0 +1,590 @@
/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
#include <what.h>
static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using LZI to provide compression and decompression.
* This is designed to provide compression without output latency.
* Flushing an LZI stream flushes all pending data to the underlying stream.
* This is essential for stream-based (e.g. networked) applications.
*
* A compressed data stream is a sequence of blocks.
* Each block is the block size followed by the compressed data.
* The last block has size zero.
* Sizes are 4-byte unsigned in network order.
*
* This format allows compressed data to be read from a stream without reading
* past the logical end of compressed data.
*
* @author Mike Wray <mike.wray@hpl.hp.com>
*/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "zlib.h"
#include "allocate.h"
#include "lzi_stream.h"
#include "file_stream.h"
#include "marshal.h"
#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
static int lzi_read(IOStream *s, void *buf, size_t size, size_t count);
static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count);
static int lzi_print(IOStream *s, const char *msg, va_list args);
static int lzi_getc(IOStream *s);
static int lzi_error(IOStream *s);
static int lzi_close(IOStream *s);
static void lzi_free(IOStream *s);
static int lzi_flush(IOStream *s);
enum {
LZI_WRITE = 1,
LZI_READ = 2,
};
/** Methods used by a gzFile* IOStream. */
static const IOMethods lzi_methods = {
read: lzi_read,
write: lzi_write,
print: lzi_print,
getc: lzi_getc,
error: lzi_error,
close: lzi_close,
free: lzi_free,
flush: lzi_flush,
};
#define BUFFER_SIZE (512 * 1024)
typedef struct LZIState {
z_stream zstream;
void *inbuf;
uint32_t inbuf_size;
void *outbuf;
uint32_t outbuf_size;
/** Underlying stream for I/O. */
IOStream *io;
/** Flags. */
int flags;
/** Error indicator. */
int error;
int eof;
int plain_bytes;
int comp_bytes;
int zstream_initialized;
int flushed;
} LZIState;
static inline int LZIState_writeable(LZIState *s){
return (s->flags & LZI_WRITE) != 0;
}
static inline int LZIState_readable(LZIState *s){
return (s->flags & LZI_READ) != 0;
}
void LZIState_free(LZIState *z){
if(!z) return;
if(z->zstream_initialized){
if(LZIState_writeable(z)){
deflateEnd(&z->zstream);
} else if(LZIState_readable(z)){
inflateEnd(&z->zstream);
}
}
deallocate(z->inbuf);
deallocate(z->outbuf);
deallocate(z);
}
static int mode_flags(const char *mode, int *flags){
int err = 0;
int r=0, w=0;
if(!mode){
err = -EINVAL;
goto exit;
}
for(; *mode; mode++){
if(*mode == 'w') w = 1;
if(*mode == 'r') r = 1;
}
if(r + w != 1){
err = -EINVAL;
goto exit;
}
if(r) *flags |= LZI_READ;
if(w) *flags |= LZI_WRITE;
exit:
return err;
}
/** Get the stream state.
*
* @param s lzi stream
* @return stream state.
*/
static inline LZIState * lzi_state(IOStream *io){
return io->data;
}
IOStream *lzi_stream_io(IOStream *io){
LZIState *s = lzi_state(io);
return s->io;
}
static inline void set_error(LZIState *s, int err){
if(err < 0 && !s->error){
s->error = err;
}
}
static int zerror(LZIState *s, int err){
if(err){
//dprintf("> err=%d\n", err);
if(err < 0) set_error(s, -EIO);
}
return s->error;
}
int lzi_stream_plain_bytes(IOStream *io){
LZIState *s = lzi_state(io);
return s->plain_bytes;
}
int lzi_stream_comp_bytes(IOStream *io){
LZIState *s = lzi_state(io);
return s->comp_bytes;
}
float lzi_stream_ratio(IOStream *io){
LZIState *s = lzi_state(io);
float ratio = 0.0;
if(s->comp_bytes){
ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
}
return ratio;
}
static int alloc(void **p, int n){
*p = allocate(n);
return (p ? 0 : -ENOMEM);
}
LZIState * LZIState_new(IOStream *io, int flags){
int err = -ENOMEM;
int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
int zstrategy = Z_DEFAULT_STRATEGY;
int zwindow = MAX_WBITS;
int zmemory = 8;
LZIState *z = ALLOCATE(LZIState);
//dprintf(">\n");
if(!z) goto exit;
z->io = io;
z->flags = flags;
if(LZIState_writeable(z)){
z->outbuf_size = BUFFER_SIZE;
/* windowBits is passed < 0 to suppress zlib header */
err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
if (err != Z_OK) goto exit;
z->zstream_initialized = 1;
err = alloc(&z->outbuf, z->outbuf_size);
if(err) goto exit;
z->zstream.next_out = z->outbuf;
z->zstream.avail_out = z->outbuf_size;
} else {
z->inbuf_size = BUFFER_SIZE;
err = alloc(&z->inbuf, z->inbuf_size);
if(err) goto exit;
///z->zstream.next_in = z->inbuf;
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
* present after the compressed stream.
*/
err = inflateInit2(&z->zstream, -zwindow);
if(err != Z_OK) goto exit;
z->zstream_initialized = 1;
}
exit:
if(err){
LZIState_free(z);
z = NULL;
}
//dprintf("< z=%p\n", z);
return z;
}
int read_block(LZIState *s){
int err = 0, k = 0;
//dprintf(">\n");
if(s->eof) goto exit;
err = unmarshal_uint32(s->io, &k);
if(err) goto exit;
if(k > s->inbuf_size){
err = -EINVAL;
goto exit;
}
if(k){
err = unmarshal_bytes(s->io, s->inbuf, k);
if(err) goto exit;
} else {
s->eof = 1;
}
s->zstream.avail_in = k;
s->zstream.next_in = s->inbuf;
s->comp_bytes += 4;
s->comp_bytes += k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
int write_block(LZIState *s){
int err = 0;
int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
int k2 = s->outbuf_size - s->zstream.avail_out;
//dprintf("> k=%d k2=%d\n", k, k2);
if(!k) goto exit;
err = marshal_uint32(s->io, k);
if(err) goto exit;
err = marshal_bytes(s->io, s->outbuf, k);
if(err) goto exit;
s->zstream.next_out = s->outbuf;
s->zstream.avail_out = s->outbuf_size;
s->comp_bytes += 4;
s->comp_bytes += k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
int write_terminator(LZIState *s){
int err = 0;
char c = 0;
err = marshal_uint32(s->io, 1);
if(err) goto exit;
err = marshal_bytes(s->io, &c, 1);
if(err) goto exit;
err = marshal_uint32(s->io, 0);
if(err) goto exit;
s->comp_bytes += 9;
exit:
return err;
}
/** Write to the underlying stream using fwrite();
*
* @param io destination
* @param buf data
* @param size size of data elements
* @param count number of data elements to write
* @return number of data elements written
*/
static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){
int err = 0;
int n = size * count;
LZIState *s = lzi_state(io);
//dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
if(!LZIState_writeable(s)){
err = -EINVAL;
goto exit;
}
s->flushed = 0;
s->zstream.next_in = (void*)buf;
s->zstream.avail_in = n;
while(s->zstream.avail_in){
if(s->zstream.avail_out == 0){
err = write_block(s);
if(err) goto exit;
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
if(err) goto exit;
}
err = n;
s->plain_bytes += n;
if(size != 1) err /= size;
exit:
//dprintf("< err=%d\n", err);
return err;
}
/** Read from the underlying stream.
*
* @param io input
* @param buf where to put input
* @param size size of data elements
* @param count number of data elements to read
* @return number of data elements read
*/
static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){
int err, zerr;
int n = size * count;
LZIState *s = lzi_state(io);
//dprintf("> size=%d count=%d n=%d\n", size, count, n);
if(!LZIState_readable(s)){
err = -EINVAL;
goto exit;
}
s->zstream.next_out = buf;
s->zstream.avail_out = n;
while(s->zstream.avail_out){
if(s->zstream.avail_in == 0){
err = read_block(s);
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
zerr = inflate(&s->zstream, Z_NO_FLUSH);
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
if(zerr == Z_STREAM_END) break;
//dprintf("> zerr=%d\n", zerr);
err = zerror(s, zerr);
if(err) goto exit;
}
err = n - s->zstream.avail_out;
s->plain_bytes += err;
if(size != 1) err /= size;
exit:
set_error(s, err);
//dprintf("< err=%d\n", err);
return err;
}
/** Print to the underlying stream.
* Returns 0 if the formatted output is too big for the internal buffer.
*
* @param io lzi stream
* @param msg format to use
* @param args arguments
* @return result of the print
*/
static int lzi_print(IOStream *io, const char *msg, va_list args){
char buf[1024];
int buf_n = sizeof(buf);
int n;
LZIState *s = lzi_state(io);
if(!LZIState_writeable(s)){
n = -EINVAL;
goto exit;
}
n = vsnprintf(buf, buf_n, (char*)msg, args);
if(n < 0) goto exit;
if(n > buf_n){
n = 0;
} else {
n = lzi_write(io, buf, 1, n);
}
exit:
return n;
}
/** Read a character from the underlying stream
*
* @param io lzi stream
* @return character read, IOSTREAM_EOF on end of file (or error)
*/
static int lzi_getc(IOStream *io){
int err;
char c;
err = lzi_read(io, &c, 1, 1);
if(err < 1) c = EOF;
err = (c==EOF ? IOSTREAM_EOF : c);
return err;
}
static int flush_output(LZIState *s, int mode){
int err = 0, zerr;
int done = 0;
int avail_out_old;
int count = 10;
//dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
if(s->flushed == 1 + mode) goto exit;
//s->zstream.avail_in = 0; /* should be zero already anyway */
for(;;){
// Write any available output.
if(done || s->zstream.avail_out == 0){
err = write_block(s);
if(err) goto exit;
if(done) break;
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
avail_out_old = s->zstream.avail_out;
zerr = deflate(&s->zstream, mode);
err = zerror(s, zerr);
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> deflate=%d\n", err);
//done = (s->zstream.avail_out != 0);
//done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
if(0 && mode == Z_FINISH){
done = (zerr == Z_STREAM_END);
} else {
done = (s->zstream.avail_in == 0)
//&& (s->zstream.avail_out == avail_out_old)
&& (s->zstream.avail_out != 0);
}
}
s->flushed = 1 + mode;
exit:
//dprintf("< err=%d\n", err);
return err;
}
/** Flush any pending input to the underlying stream.
*
* @param s lzi stream
* @return 0 on success, error code otherwise
*/
static int lzi_flush(IOStream *io){
int err = 0;
LZIState *s = lzi_state(io);
//dprintf(">\n");
if(!LZIState_writeable(s)){
err = -EINVAL;
goto exit;
}
err = flush_output(s, Z_SYNC_FLUSH);
if(err) goto exit;
err = IOStream_flush(s->io);
exit:
set_error(s, err);
//dprintf("< err=%d\n", err);
return (err < 0 ? err : 0);
}
/** Check if a stream has an error.
*
* @param s lzi stream
* @return code if has an error, 0 otherwise
*/
static int lzi_error(IOStream *s){
int err = 0;
LZIState *state = lzi_state(s);
err = state->error;
if(err) goto exit;
err = IOStream_error(state->io);
exit:
return err;
}
/** Close an lzi stream.
*
* @param s lzi stream to close
* @return result of the close
*/
static int lzi_close(IOStream *io){
int err = 0;
LZIState *s = lzi_state(io);
if(LZIState_writeable(s)){
err = flush_output(s, Z_FINISH);
if(err) goto exit;
err = write_terminator(s);
if(err) goto exit;
err = IOStream_flush(s->io);
}
exit:
err = IOStream_close(s->io);
set_error(s, err);
return err;
}
/** Free an lzi stream.
*
* @param s lzi stream
*/
static void lzi_free(IOStream *s){
LZIState *state = lzi_state(s);
IOStream_free(state->io);
LZIState_free(state);
s->data = NULL;
}
/** Create an lzi stream for an IOStream.
*
* @param io stream to wrap
* @return new IOStream using f for i/o
*/
IOStream *lzi_stream_new(IOStream *io, const char *mode){
int err = -ENOMEM;
int flags = 0;
IOStream *zio = NULL;
LZIState *state = NULL;
zio = ALLOCATE(IOStream);
if(!zio) goto exit;
err = mode_flags(mode, &flags);
if(err) goto exit;
state = LZIState_new(io, flags);
if(!state) goto exit;
err = 0;
zio->data = state;
zio->methods = &lzi_methods;
exit:
if(err){
if(state) LZIState_free(state);
if(zio) deallocate(zio);
zio = NULL;
}
return zio;
}
/** IOStream version of fdopen().
*
* @param fd file descriptor
* @param flags giving the mode to open in (as for fdopen())
* @return new stream for the open file, or NULL if failed
*/
IOStream *lzi_stream_fdopen(int fd, const char *mode){
int err = -ENOMEM;
IOStream *io = NULL, *zio = NULL;
io = file_stream_fdopen(fd, mode);
if(!io) goto exit;
zio = lzi_stream_new(io, mode);
if(!io) goto exit;
err = 0;
exit:
if(err){
IOStream_free(io);
IOStream_free(zio);
zio = NULL;
}
return zio;
}
#endif
+36
View File
@@ -0,0 +1,36 @@
#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_LZI_STREAM_H_
#define _SP_LZI_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
extern IOStream *lzi_stream_io(IOStream *zio);
extern int lzi_stream_plain_bytes(IOStream *io);
extern int lzi_stream_comp_bytes(IOStream *io);
extern float lzi_stream_ratio(IOStream *io);
#endif
#endif /* !_SP_FILE_STREAM_H_ */
+596
View File
@@ -0,0 +1,596 @@
/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
#include <what.h>
static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using LZO to provide compression and decompression.
* This is designed to provide reasonable compression without output latency.
* Flushing an LZO stream flushes all pending data to the underlying stream.
* This is essential for stream-based (e.g. networked) applications.
*
* A compressed data stream is a sequence of blocks.
* Each block except the last is the plain data size followed by the compressed data size
* and the compressed data. The last block has plain data size zero and omits the rest.
* Sizes are 4-byte unsigned in network order. If the compressed size is smaller than
* the plain size the block data is compressed, otherwise it is plain (uncompressed).
*
* This format allows compressed data to be read from a stream without reading
* past the logical end of compressed data.
*
* @author Mike Wray <mike.wray@hpl.hp.com>
*/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "lzo1x.h"
#include "allocate.h"
#include "lzo_stream.h"
#include "file_stream.h"
#include "marshal.h"
#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args)
static int lzo_read(IOStream *s, void *buf, size_t size, size_t count);
static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count);
static int lzo_print(IOStream *s, const char *msg, va_list args);
static int lzo_getc(IOStream *s);
static int lzo_error(IOStream *s);
static int lzo_close(IOStream *s);
static void lzo_free(IOStream *s);
static int lzo_flush(IOStream *s);
enum {
LZO_WRITE = 1,
LZO_READ = 2,
};
/** Methods used by a gzFile* IOStream. */
static const IOMethods lzo_methods = {
read: lzo_read,
write: lzo_write,
print: lzo_print,
getc: lzo_getc,
error: lzo_error,
close: lzo_close,
free: lzo_free,
flush: lzo_flush,
};
//#define PLAIN_SIZE (64 * 1024)
//#define PLAIN_SIZE (128 * 1024)
#define PLAIN_SIZE (512 * 1024)
//#define NOCOMPRESS
typedef struct LZOState {
/** Flags. */
int flags;
/** Error indicator. */
int error;
/** Underlying stream for I/O. */
IOStream *io;
/** Working memory (only needed for compression, not decompression). */
lzo_byte *memory;
/** Buffer for plain (uncompressed) data. */
lzo_byte *plain;
/** Size of the plain buffer. */
lzo_uint plain_size;
/** Pointer into the plain buffer. */
lzo_byte *plain_ptr;
/** Number of bytes of plain data available. */
lzo_uint plain_n;
/** Buffer for compressed data. */
lzo_byte *comp;
/** Size of the compressed buffer. */
lzo_uint comp_size;
int plain_bytes;
int comp_bytes;
} LZOState;
void LZOState_free(LZOState *z){
if(!z) return;
deallocate(z->memory);
deallocate(z->plain);
deallocate(z->comp);
deallocate(z);
}
/** Maximum size of compressed data for the given plain data size.
*
* @param plain_size size of plain data
* @return maximum size of compressed data
*/
static int comp_size(int plain_size){
return plain_size + (plain_size / 64) + 16 + 3;
}
static int mode_flags(const char *mode, int *flags){
int err = 0;
int r=0, w=0;
if(!mode){
err = -EINVAL;
goto exit;
}
for(; *mode; mode++){
if(*mode == 'w') w = 1;
if(*mode == 'r') r = 1;
}
if(r + w != 1){
err = -EINVAL;
goto exit;
}
if(r) *flags |= LZO_READ;
if(w) *flags |= LZO_WRITE;
exit:
return err;
}
/** Get the stream state.
*
* @param s lzo stream
* @return stream state.
*/
static inline LZOState * lzo_state(IOStream *s){
return s->data;
}
IOStream *lzo_stream_io(IOStream *s){
LZOState *state = lzo_state(s);
return state->io;
}
static inline void set_error(LZOState *state, int err){
if(err < 0 && !state->error){
state->error = err;
}
}
int lzo_stream_plain_bytes(IOStream *s){
LZOState *state = lzo_state(s);
return state->plain_bytes;
}
int lzo_stream_comp_bytes(IOStream *s){
LZOState *state = lzo_state(s);
return state->comp_bytes;
}
float lzo_stream_ratio(IOStream *s){
LZOState *state = lzo_state(s);
float ratio = 0.0;
if(state->comp_bytes){
ratio = ((float) state->comp_bytes)/((float) state->plain_bytes);
}
return ratio;
}
static inline int LZOState_writeable(LZOState *state){
return (state->flags & LZO_WRITE) != 0;
}
static inline int LZOState_readable(LZOState *state){
return (state->flags & LZO_READ) != 0;
}
LZOState * LZOState_new(IOStream *io, int flags){
int err = -ENOMEM;
LZOState *z = ALLOCATE(LZOState);
//dprintf(">\n");
if(!z) goto exit;
z->io = io;
z->flags = flags;
if(LZOState_writeable(z)){
z->memory = allocate(LZO1X_1_MEM_COMPRESS);
if(!z->memory) goto exit;
}
z->plain_size = PLAIN_SIZE;
z->plain = allocate(z->plain_size);
if(!z->plain) goto exit;
z->plain_ptr = z->plain;
z->comp_size = comp_size(z->plain_size);
z->comp = allocate(z->comp_size);
if(!z->comp) goto exit;
err = 0;
exit:
if(err){
LZOState_free(z);
z = NULL;
}
//dprintf("< z=%p\n", z);
return z;
}
static int lzo_compress(LZOState *state){
int err = 0;
int k, comp_n;
//dprintf(">\n");
//dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory);
// Compress the plain buffer.
err = lzo1x_1_compress(state->plain, state->plain_n,
state->comp, &comp_n,
state->memory);
//dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n);
// Write plain size, compressed size.
err = marshal_uint32(state->io, state->plain_n);
if(err) goto exit;
err = marshal_uint32(state->io, comp_n);
if(err) goto exit;
//dprintf("> write data...\n");
// Write the smaller of the compressed and plain data.
if(state->plain_n < comp_n){
k = state->plain_n;
err = marshal_bytes(state->io, state->plain, state->plain_n);
} else {
k = comp_n;
err = marshal_bytes(state->io, state->comp, comp_n);
}
if(err) goto exit;
// Total output bytes.
k+= 8;
//dprintf("> wrote %d bytes\n", k);
state->plain_bytes += state->plain_n;
state->comp_bytes += k;
//dprintf("> plain=%d, comp=%d, ratio=%3.2f\n",
// state->plain_bytes, state->comp_bytes,
// ((float)state->comp_bytes)/((float)state->plain_bytes));
// Reset the plain buffer.
state->plain_ptr = state->plain;
state->plain_n = 0;
err = k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
static int lzo_decompress(LZOState *state){
int plain_n, comp_n;
int err, k;
//dprintf(">\n");
err = unmarshal_uint32(state->io, &plain_n);
//dprintf("> err=%d plain_n=%d\n", err, plain_n);
if(err) goto exit;
state->comp_bytes += 4;
if(plain_n == 0) goto exit;
err = unmarshal_uint32(state->io, &comp_n);
//dprintf("> err=%d comp_n=%d\n", err, comp_n);
if(err) goto exit;
state->comp_bytes += 4;
if(plain_n > state->plain_size){
err = -EINVAL;
goto exit;
}
if(comp_n > plain_n){
//dprintf("> reading plain data %d...\n", plain_n);
k = plain_n;
err = unmarshal_bytes(state->io, state->plain, plain_n);
state->plain_n = plain_n;
} else {
//dprintf("> reading comp data %d...\n", comp_n);
k = comp_n;
err = unmarshal_bytes(state->io, state->comp, comp_n);
//dprintf("> decompress comp_n=%d\n", comp_n);
err = lzo1x_decompress(state->comp, comp_n,
state->plain, &state->plain_n,
state->memory);
//dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n);
if(err != LZO_E_OK || state->plain_n != plain_n){
// Bad. Corrupted input.
err = -EINVAL;
eprintf("> Corrupted!\n");
goto exit;
}
}
state->comp_bytes += k;
state->plain_bytes += state->plain_n;
state->plain_ptr = state->plain;
err = k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
/** Write to the underlying stream using fwrite();
*
* @param stream destination
* @param buf data
* @param size size of data elements
* @param count number of data elements to write
* @return number of data elements written
*/
static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){
int err = 0;
int n = size * count; // Total number of bytes to write.
int chunk; // Size of chunk to write.
int remaining; // Number of bytes remaining to write.
int space; // Amount of space left in plain buffer.
LZOState *state = lzo_state(s);
#ifdef NOCOMPRESS
//dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
err = IOStream_write(state->io, buf, size, count);
//dprintf("< err=%d\n", err);
#else
//dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
remaining = n;
space = state->plain_size - state->plain_n;
//dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n",
// state->plain, state->plain_ptr, state->plain_n, space);
while(remaining){
chunk = remaining;
if(chunk > space) chunk = space;
//dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk);
memcpy(state->plain_ptr, buf, chunk);
remaining -= chunk;
space -= chunk;
state->plain_ptr += chunk;
state->plain_n += chunk;
if(space == 0){
// Input buffer is full. Compress and write it.
err = lzo_compress(state);
if(err < 0) goto exit;
space = state->plain_size - state->plain_n;
}
}
err = (size > 1 ? n / size : n);
exit:
set_error(state, err);
#endif
return err;
}
/** Read from the underlying stream.
*
* @param stream input
* @param buf where to put input
* @param size size of data elements
* @param count number of data elements to read
* @return number of data elements read
*/
static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){
int err = 0;
int k = 0; // Number of (plain) bytes read.
int remaining = size * count; // Number of bytes remaining to read.
int chunk; // Size of chunk to read.
LZOState *state = lzo_state(s);
#ifdef NOCOMPRESS
//dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
err = IOStream_read(state->io, buf, size, count);
//dprintf("< err=%d\n", err);
#else
if(!(state->flags & LZO_READ)){
err = -EINVAL;
goto exit;
}
while(remaining){
if(state->plain_n == 0){
// No more plain input, decompress some more.
err = lzo_decompress(state);
if(err < 0) goto exit;
// Stop reading if there is no more input.
if(err == 0 || state->plain_n == 0) break;
}
chunk = remaining;
if(chunk > state->plain_n) chunk = state->plain_n;
memcpy(buf, state->plain_ptr, chunk);
k += chunk;
buf += chunk;
state->plain_ptr += chunk;
state->plain_n -= chunk;
remaining -= chunk;
}
err = k;
exit:
set_error(state, err);
#endif
return err;
}
/** Print to the underlying stream.
* Returns 0 if the formatted output is too big for the internal buffer.
*
* @param s lzo stream
* @param msg format to use
* @param args arguments
* @return result of the print
*/
static int lzo_print(IOStream *s, const char *msg, va_list args){
char buf[1024];
int buf_n = sizeof(buf);
int n;
LZOState *state = lzo_state(s);
if(!LZOState_writeable(state)){
n = -EINVAL;
goto exit;
}
n = vsnprintf(buf, buf_n, (char*)msg, args);
if(n < 0) goto exit;
if(n > buf_n){
n = 0;
} else {
n = lzo_write(s, buf, 1, n);
}
exit:
return n;
}
/** Read a character from the underlying stream
*
* @param s lzo stream
* @return character read, IOSTREAM_EOF on end of file (or error)
*/
static int lzo_getc(IOStream *s){
int err;
char c;
err = lzo_read(s, &c, 1, 1);
if(err < 1) c = EOF;
err = (c==EOF ? IOSTREAM_EOF : c);
return err;
}
/** Flush any pending input to the underlying stream.
*
* @param s lzo stream
* @return 0 on success, error code otherwise
*/
static int lzo_flush(IOStream *s){
int err = 0;
LZOState *state = lzo_state(s);
//dprintf(">\n");
#ifdef NOCOMPRESS
err = IOStream_flush(state->io);
#else
if(!LZOState_writeable(state)){
err = -EINVAL;
goto exit;
}
if(state->plain_n){
err = lzo_compress(state);
if(err < 0) goto exit;
}
err = IOStream_flush(state->io);
exit:
set_error(state, err);
#endif
//dprintf("< err=%d\n", err);
return (err < 0 ? err : 0);
}
/** Check if a stream has an error.
*
* @param s lzo stream
* @return code if has an error, 0 otherwise
*/
static int lzo_error(IOStream *s){
int err = 0;
LZOState *state = lzo_state(s);
err = state->error;
if(err) goto exit;
err = IOStream_error(state->io);
exit:
return err;
}
int lzo_stream_finish(IOStream *s){
int err = 0;
LZOState *state = lzo_state(s);
if(!LZOState_writeable(state)){
err = -EINVAL;
goto exit;
}
err = lzo_flush(s);
if(err < 0) goto exit;
err = marshal_int32(state->io, 0);
exit:
return err;
}
/** Close an lzo stream.
*
* @param s lzo stream to close
* @return result of the close
*/
static int lzo_close(IOStream *s){
int err = 0;
LZOState *state = lzo_state(s);
#ifdef NOCOMPRESS
err = IOStream_close(state->io);
#else
if(LZOState_writeable(state)){
err = lzo_stream_finish(s);
}
err = IOStream_close(state->io);
set_error(state, err);
#endif
return err;
}
/** Free an lzo stream.
*
* @param s lzo stream
*/
static void lzo_free(IOStream *s){
LZOState *state = lzo_state(s);
IOStream_free(state->io);
LZOState_free(state);
s->data = NULL;
}
/** Create an lzo stream for an IOStream.
*
* @param io stream to wrap
* @return new IOStream using f for i/o
*/
IOStream *lzo_stream_new(IOStream *io, const char *mode){
int err = -ENOMEM;
int flags = 0;
IOStream *zio = NULL;
LZOState *state = NULL;
zio = ALLOCATE(IOStream);
if(!zio) goto exit;
err = mode_flags(mode, &flags);
if(err) goto exit;
state = LZOState_new(io, flags);
if(!state) goto exit;
err = 0;
zio->data = state;
zio->methods = &lzo_methods;
exit:
if(err){
if(state) LZOState_free(state);
if(zio) deallocate(zio);
zio = NULL;
}
return zio;
}
/** IOStream version of fdopen().
*
* @param fd file descriptor
* @param flags giving the mode to open in (as for fdopen())
* @return new stream for the open file, or NULL if failed
*/
IOStream *lzo_stream_fdopen(int fd, const char *mode){
int err = -ENOMEM;
IOStream *io = NULL, *zio = NULL;
io = file_stream_fdopen(fd, mode);
if(!io) goto exit;
zio = lzo_stream_new(io, mode);
if(!io) goto exit;
err = 0;
exit:
if(err){
IOStream_free(io);
IOStream_free(zio);
zio = NULL;
}
return zio;
}
#endif
+36
View File
@@ -0,0 +1,36 @@
#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_LZO_STREAM_H_
#define _SP_LZO_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
extern IOStream *lzo_stream_new(IOStream *io, const char *mode);
extern IOStream *lzo_stream_fopen(const char *file, const char *mode);
extern IOStream *lzo_stream_fdopen(int fd, const char *mode);
extern IOStream *lzo_stream_io(IOStream *zio);
extern int lzo_stream_plain_bytes(IOStream *io);
extern int lzo_stream_comp_bytes(IOStream *io);
extern float lzo_stream_ratio(IOStream *io);
#endif
#endif /* !_SP_FILE_STREAM_H_ */
+207
View File
@@ -0,0 +1,207 @@
#include <errno.h>
#include "sys_net.h"
#include "allocate.h"
#include "marshal.h"
#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
/* Messages are coded as msgid followed by message fields.
* Initial message on any channel is hello - so can check version
* compatibility.
*
* char* -> uint16_t:n <n bytes>
* ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
* optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
* lists go as ('1' <elt>)* '0'
*/
int marshal_flush(IOStream *io){
int err = 0;
err = IOStream_flush(io);
return err;
}
int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
int err = 0;
int n;
n = IOStream_write(io, s, s_n);
if(n < 0){
err = n;
} else if (n < s_n){
wprintf("> Wanted %d, got %d\n", s_n, n);
err = -EIO;
}
return err;
}
int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
int err = 0;
int n;
//dprintf("> s_n=%d\n", s_n);
n = IOStream_read(io, s, s_n);
//dprintf("> n=%d\n", n);
if(n < 0){
err = n;
} else if(n < s_n){
wprintf("> Wanted %d, got %d\n", s_n, n);
err = -EIO;
}
//dprintf("< err=%d\n", err);
return err;
}
int marshal_uint8(IOStream *io, uint8_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_uint8(IOStream *io, uint8_t *x){
return unmarshal_bytes(io, x, sizeof(*x));
}
int marshal_uint16(IOStream *io, uint16_t x){
x = htons(x);
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_uint16(IOStream *io, uint16_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohs(*x);
return err;
}
int marshal_int32(IOStream *io, int32_t x){
int err = 0;
//dprintf("> x=%d\n", x);
x = htonl(x);
err = marshal_bytes(io, &x, sizeof(x));
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_int32(IOStream *io, int32_t *x){
int err = 0;
//dprintf(">\n");
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohl(*x);
//dprintf("< err=%d x=%d\n", err, *x);
return err;
}
int marshal_uint32(IOStream *io, uint32_t x){
int err = 0;
//dprintf("> x=%u\n", x);
x = htonl(x);
err = marshal_bytes(io, &x, sizeof(x));
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_uint32(IOStream *io, uint32_t *x){
int err = 0;
//dprintf(">\n");
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohl(*x);
//dprintf("< err=%d x=%u\n", err, *x);
return err;
}
int marshal_uint64(IOStream *io, uint64_t x){
int err;
err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
if(err) goto exit;
err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff));
exit:
return err;
}
int unmarshal_uint64(IOStream *io, uint64_t *x){
int err = 0;
uint32_t hi, lo;
err = unmarshal_uint32(io, &hi);
if(err) goto exit;
err = unmarshal_uint32(io, &lo);
*x = (((uint64_t) hi) << 32) | lo;
exit:
return err;
}
int marshal_net16(IOStream *io, net16_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_net16(IOStream *io, net16_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
return err;
}
int marshal_net32(IOStream *io, net32_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_net32(IOStream *io, net32_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
return err;
}
int marshal_string(IOStream *io, char *s, uint32_t s_n){
int err;
//dprintf("> s=%s\n", s);
err = marshal_uint32(io, s_n);
if(err) goto exit;
err = marshal_bytes(io, s, s_n);
exit:
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
int err = 0, val_n = 0;
//dprintf(">\n");
err = unmarshal_uint32(io, &val_n);
if(err) goto exit;
if(val_n >= s_n){
err = -EINVAL;
goto exit;
}
err = unmarshal_bytes(io, s, val_n);
if(err) goto exit;
s[val_n] = '\0';
exit:
//dprintf("< err=%d s=%s\n", err, s);
return err;
}
int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
int err = 0, val_n = 0;
char *val = NULL;
//dprintf(">\n");
err = unmarshal_uint32(io, &val_n);
if(err) goto exit;
val = allocate(val_n + 1);
if(!val){
err = -ENOMEM;
goto exit;
}
err = unmarshal_bytes(io, val, val_n);
if(err) goto exit;
val[val_n] = '\0';
exit:
if(err){
if(val) deallocate(val);
val = NULL;
val_n = 0;
}
*s = val;
if(s_n) *s_n = val_n;
//dprintf("< err=%d s=%s\n", err, *s);
return err;
}
+43
View File
@@ -0,0 +1,43 @@
/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
#ifndef _SP_MARSHAL_H_
#define _SP_MARSHAL_H_
#include "iostream.h"
/** A 16-bit uint in network order, e.g. a port number. */
typedef uint16_t net16_t;
/** A 32-bit uint in network order, e.g. an IP address. */
typedef uint32_t net32_t;
extern int marshal_flush(IOStream *io);
extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
extern int marshal_uint8(IOStream *io, uint8_t x);
extern int unmarshal_uint8(IOStream *io, uint8_t *x);
extern int marshal_uint16(IOStream *io, uint16_t x);
extern int unmarshal_uint16(IOStream *io, uint16_t *x);
extern int marshal_uint32(IOStream *io, uint32_t x);
extern int unmarshal_uint32(IOStream *io, uint32_t *x);
extern int marshal_int32(IOStream *io, int32_t x);
extern int unmarshal_int32(IOStream *io, int32_t *x);
extern int marshal_uint64(IOStream *io, uint64_t x);
extern int unmarshal_uint64(IOStream *io, uint64_t *x);
extern int marshal_net16(IOStream *io, net16_t x);
extern int unmarshal_net16(IOStream *io, net16_t *x);
extern int marshal_net32(IOStream *io, net32_t x);
extern int unmarshal_net32(IOStream *io, net32_t *x);
extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
#endif /* ! _SP_MARSHAL_H_ */
+259
View File
@@ -0,0 +1,259 @@
/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */
/*
* Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using sockets.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "allocate.h"
#include "socket_stream.h"
#define MODULE_NAME "sock"
#define DEBUG 0
//#undef DEBUG
#include "debug.h"
static int socket_read(IOStream *s, void *buf, size_t n);
static int socket_write(IOStream *s, const void *buf, size_t n);
static int socket_error(IOStream *s);
static int socket_close(IOStream *s);
static void socket_free(IOStream *s);
static int socket_flush(IOStream *s);
/** Methods used by a socket IOStream. */
static const IOMethods socket_methods = {
read: socket_read,
write: socket_write,
error: socket_error,
close: socket_close,
free: socket_free,
flush: socket_flush,
};
/** Get the socket data.
*
* @param io socket stream
* @return data
*/
static inline SocketData * socket_data(IOStream *io){
return (SocketData *)io->data;
}
/** Test if a stream is a socket stream.
*
* @param io stream
* @return 0 if a socket stream, -EINVAL if not
*/
int socket_stream_check(IOStream *io){
return (io && io->methods == &socket_methods ? 0 : -EINVAL);
}
/** Get the data for a socket stream.
*
* @param io stream
* @param data return value for the data
* @return 0 if a socket stream, -EINVAL if not
*/
int socket_stream_data(IOStream *io, SocketData **data){
int err = socket_stream_check(io);
if(err){
*data = NULL;
} else {
*data = socket_data(io);
}
return err;
}
/** Set the destination address for a socket stream.
*
* @param io stream
* @param addr address
* @return 0 if a socket stream, -EINVAL if not
*/
int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
int err = 0;
SocketData *data = NULL;
err = socket_stream_data(io, &data);
if(!err){
data->daddr = *addr;
}
return err;
}
/** Set the send flags for a socket stream.
*
* @param io stream
* @param flags flags
* @return 0 if a socket stream, -EINVAL if not
*/
int socket_stream_set_flags(IOStream *io, int flags){
int err = 0;
SocketData *data = NULL;
err = socket_stream_data(io, &data);
if(!err){
data->flags = flags;
}
return err;
}
/** Write to the underlying socket using sendto.
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to write
* @return number of bytes written
*/
static int socket_write(IOStream *s, const void *buf, size_t n){
SocketData *data = socket_data(s);
struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
socklen_t daddr_n = sizeof(data->daddr);
int k;
dprintf("> sock=%d addr=%s:%d n=%d\n",
data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
if(0){
struct sockaddr_in self = {};
socklen_t self_n;
getsockname(data->fd, (struct sockaddr *)&self, &self_n);
dprintf("> sockname sock=%d %s:%d\n",
data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
}
k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
dprintf("> sendto=%d\n", k);
return k;
}
/** Read from the underlying stream using recv();
*
* @param stream input
* @param buf where to put input
* @param n number of bytes to read
* @return number of bytes read
*/
static int socket_read(IOStream *s, void *buf, size_t n){
SocketData *data = socket_data(s);
int k;
struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
socklen_t saddr_n = sizeof(data->saddr);
k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
return k;
}
/** Print to the underlying socket.
*
* @param s socket stream
* @param msg format to use
* @param args arguments
* @return result of the print
*/
static int socket_print(IOStream *s, const char *msg, va_list args){
SocketData *data = socket_data(s);
int n;
n = vsnprintf(data->buf, data->buf_n - 1, msg, args);
if(0 < n && n < data->buf_n){
socket_write(s, data->buf, n);
}
return n;
}
/** Read a character from the underlying socket
*
* @param s socket stream
* @return character read, IOSTREAM_EOF on end of socket (or error)
*/
static int socket_getc(IOStream *s){
char b;
int n, c;
n = socket_read(s, &b, 1);
c = (n <= 0 ? IOSTREAM_EOF : b);
return c;
}
/** Flush the socket (no-op).
*
* @param s socket stream
* @return 0 on success, error code otherwise
*/
static int socket_flush(IOStream *s){
return 0;
}
/** Check if a socket stream has an error (no-op).
*
* @param s socket stream
* @return 1 if has an error, 0 otherwise
*/
static int socket_error(IOStream *s){
// Read SOL_SOCKET/SO_ERROR ?
return 0;
}
/** Close a socket stream.
*
* @param s socket stream to close
* @return result of the close
*/
static int socket_close(IOStream *s){
SocketData *data = socket_data(s);
return close(data->fd);
}
/** Free a socket stream.
*
* @param s socket stream
*/
static void socket_free(IOStream *s){
SocketData *data = socket_data(s);
deallocate(data);
}
/** Create an IOStream for a socket.
*
* @param fd socket to wtap
* @return new IOStream using fd for i/o
*/
IOStream *socket_stream_new(int fd){
int err = -ENOMEM;
IOStream *io = NULL;
SocketData *data = NULL;
io = ALLOCATE(IOStream);
if(!io) goto exit;
io->methods = &socket_methods;
data = ALLOCATE(SocketData);
if(!data) goto exit;
io->data = data;
data->fd = fd;
data->buf_n = sizeof(data->buf);
err = 0;
exit:
if(err){
if(io){
if(data) deallocate(data);
deallocate(io);
io = NULL;
}
}
return io;
}
+54
View File
@@ -0,0 +1,54 @@
/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */
/*
* Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SOCKET_STREAM_H_
#define _XEN_LIB_SOCKET_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/** Data associated with a socket stream. */
typedef struct SocketData {
/** The socket file descriptor. */
int fd;
/** Source address from last read (recvfrom). */
struct sockaddr_in saddr;
/** Destination address for writes (sendto). */
struct sockaddr_in daddr;
/** Write flags (sendto). */
int flags;
/** Buffer size. */
int buf_n;
/** Buffer for formatted printing. */
char buf[1024];
} SocketData;
extern IOStream *socket_stream_new(int fd);
extern int socket_stream_data(IOStream *io, SocketData **data);
extern int socket_stream_check(IOStream *io);
extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
extern int socket_stream_set_flags(IOStream *io, int flags);
#endif
#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
+174
View File
@@ -0,0 +1,174 @@
/*
* Copyright (C) 2001, 2002 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* IOStream subtype for input and output to strings.
* Usable from user or kernel code (with __KERNEL__ defined).
*/
#include "sys_string.h"
#include "string_stream.h"
#include "allocate.h"
static int string_print(IOStream *io, const char *msg, va_list args);
static int string_getc(IOStream *io);
static int string_error(IOStream *io);
static int string_close(IOStream *io);
static void string_free(IOStream *io);
/** Methods for a string stream. */
static IOMethods string_methods = {
//print: string_print,
//getc: string_getc,
error: string_error,
close: string_close,
free: string_free,
};
/** Get the string stream state.
*
* @param io string stream
* @return state
*/
static inline StringData *get_string_data(IOStream *io){
return (StringData*)io->data;
}
/** Read a character from a string stream.
*
* @param io string stream
* @return character read, IOSTREAM_EOF if no more input
*/
static int string_getc(IOStream *io){
StringData *data = get_string_data(io);
int c = IOSTREAM_EOF;
char *s = data->in;
if(s && s < data->end){
c = (unsigned)*s;
data->in = s+1;
}
return c;
}
/** Print to a string stream.
* Formats the data to an internal buffer and prints it.
* The formatted data must fit into the internal buffer.
*
* @param io string stream
* @param format print format
* @param args print arguments
* @return result of the print
*/
static int string_print(IOStream *io, const char *msg, va_list args){
StringData *data = get_string_data(io);
int k = data->end - data->out;
int n = vsnprintf(data->out, k, (char*)msg, args);
if(n < 0 || n > k ){
n = k;
IOStream_close(io);
} else {
data->out += n;
}
return n;
}
/** Test if a string stream has an error.
*
* @param io string stream
* @return 0 if ok, error code otherwise
*/
static int string_error(IOStream *io){
StringData *data = get_string_data(io);
return data->out == NULL;
}
/** Close a string stream.
*
* @param io string stream
* @return 0
*/
static int string_close(IOStream *io){
StringData *data = get_string_data(io);
data->in = NULL;
data->out = NULL;
return 0;
}
/** Free a string stream.
* The stream must have been allocated, not statically created.
* The stream state is freed, but the underlying string is not.
*
* @param io string stream
*/
static void string_free(IOStream *io){
StringData *data = get_string_data(io);
zero(data, sizeof(*data));
deallocate(data);
}
/** Get the methods to use for a string stream.
*
* @return methods
*/
IOMethods *string_stream_get_methods(void){
return &string_methods;
}
/** Initialise a string stream, usually from static data.
*
* @param io address of IOStream to fill in
* @param data address of StringData to fill in
* @param s string to use
* @param n length of the string
*/
void string_stream_init(IOStream *io, StringData *data, char *s, int n){
if(data && io){
zero(data, sizeof(*data));
data->string = (char*)s;
data->in = data->string;
data->out = data->string;
data->size = n;
data->end = data->string + n;
zero(io, sizeof(*io));
io->methods = &string_methods;
io->data = data;
}
}
/** Allocate and initialise a string stream.
*
* @param s string to use
* @param n length of the string
* @return new stream (free using IOStream_free)
*/
IOStream *string_stream_new(char *s, int n){
int ok = 0;
StringData *data = ALLOCATE(StringData);
IOStream *io = ALLOCATE(IOStream);
if(data && io){
ok = 1;
string_stream_init(io, data, s, n);
}
if(!ok){
deallocate(data);
deallocate(io);
io = NULL;
}
return io;
}
+46
View File
@@ -0,0 +1,46 @@
/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
/*
* Copyright (C) 2001, 2002 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_STRING_STREAM_H_
#define _SP_STRING_STREAM_H_
#include "iostream.h"
/** Internal state for a string stream.
* Exposed here so that string streams can be statically created, using
* string_stream_init().
*/
typedef struct {
/** The string used for input and ouput. */
char *string;
/** Output pointer. */
char *out;
/** Input pointer. */
char *in;
/** Length of string. */
int size;
/** End marker. */
char *end;
} StringData;
extern IOMethods *string_stream_get_methods(void);
extern IOStream *string_stream_new(char *s, int n);
extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
#endif /* !_SP_STRING_STREAM_H_ */
+935
View File
@@ -0,0 +1,935 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include "sys_string.h"
#include "lexis.h"
#include "sys_net.h"
#include "hash_table.h"
#include "sxpr.h"
#include <errno.h>
#undef free
/** @file
* General representation of sxprs.
* Includes print, equal, and free functions for the sxpr types.
*
* Zero memory containing an Sxpr will have the value ONONE - this is intentional.
* When a function returning an sxpr cannot allocate memory we return ONOMEM.
*
*/
static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
static int atom_equal(Sxpr x, Sxpr y);
static void atom_free(Sxpr obj);
static int string_print(IOStream *io, Sxpr obj, unsigned flags);
static int string_equal(Sxpr x, Sxpr y);
static void string_free(Sxpr obj);
static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
static int cons_equal(Sxpr x, Sxpr y);
static void cons_free(Sxpr obj);
static int null_print(IOStream *io, Sxpr obj, unsigned flags);
static int none_print(IOStream *io, Sxpr obj, unsigned flags);
static int int_print(IOStream *io, Sxpr obj, unsigned flags);
static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
/** Type definitions. */
static SxprType types[1024] = {
[T_NONE] { type: T_NONE, name: "none", print: none_print },
[T_NULL] { type: T_NULL, name: "null", print: null_print },
[T_UINT] { type: T_UINT, name: "int", print: int_print, },
[T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
[T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
pointer: TRUE,
free: atom_free,
equal: atom_equal,
},
[T_STRING] { type: T_STRING, name: "string", print: string_print,
pointer: TRUE,
free: string_free,
equal: string_equal,
},
[T_CONS] { type: T_CONS, name: "cons", print: cons_print,
pointer: TRUE,
free: cons_free,
equal: cons_equal,
},
};
/** Number of entries in the types array. */
static int type_sup = sizeof(types)/sizeof(types[0]);
/** Get the type definition for a given type code.
*
* @param ty type code
* @return type definition or null
*/
SxprType *get_sxpr_type(int ty){
if(0 <= ty && ty < type_sup){
return types+ty;
}
return NULL;
}
/** The default print function.
*
* @param io stream to print to
* @param x sxpr to print
* @param flags print flags
* @return number of bytes written on success
*/
int default_print(IOStream *io, Sxpr x, unsigned flags){
return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
}
/** The default equal function.
* Uses eq().
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int default_equal(Sxpr x, Sxpr y){
return eq(x, y);
}
/** General sxpr print function.
* Prints an sxpr on a stream using the print function for the sxpr type.
* Printing is controlled by flags from the PrintFlags enum.
* If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
* (for debugging).
*
* @param io stream to print to
* @param x sxpr to print
* @param flags print flags
* @return number of bytes written
*/
int objprint(IOStream *io, Sxpr x, unsigned flags){
SxprType *def = get_sxpr_type(get_type(x));
ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
int k = 0;
if(!io) return k;
if(flags & PRINT_TYPE){
k += IOStream_print(io, "%s:", def->name);
}
k += print_fn(io, x, flags);
return k;
}
/** General sxpr free function.
* Frees an sxpr using the free function for its type.
* Free functions must recursively free any subsxprs.
* If no function is defined then the default is to
* free sxprs whose type has pointer true.
* Sxprs must not be used after freeing.
*
* @param x sxpr to free
*/
void objfree(Sxpr x){
SxprType *def = get_sxpr_type(get_type(x));
if(def){
if(def->free){
def->free(x);
} else if (def->pointer){
hfree(x);
}
}
}
/** General sxpr equality function.
* Compares x and y using the equal function for x.
* Uses default_equal() if x has no equal function.
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int objequal(Sxpr x, Sxpr y){
SxprType *def = get_sxpr_type(get_type(x));
ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
return equal_fn(x, y);
}
/** Search for a key in an alist.
* An alist is a list of conses, where the cars
* of the conses are the keys. Compares keys using equality.
*
* @param k key
* @param l alist to search
* @return first element of l with car k, or ONULL
*/
Sxpr assoc(Sxpr k, Sxpr l){
for( ; CONSP(l) ; l = CDR(l)){
Sxpr x = CAR(l);
if(CONSP(x) && objequal(k, CAR(x))){
return x;
}
}
return ONULL;
}
/** Search for a key in an alist.
* An alist is a list of conses, where the cars
* of the conses are the keys. Compares keys using eq.
*
* @param k key
* @param l alist to search
* @return first element of l with car k, or ONULL
*/
Sxpr assocq(Sxpr k, Sxpr l){
for( ; CONSP(l); l = CDR(l)){
Sxpr x = CAR(l);
if(CONSP(x) && eq(k, CAR(x))){
return x;
}
}
return ONULL;
}
/** Add a new key and value to an alist.
*
* @param k key
* @param l value
* @param l alist
* @return l with the new cell added to the front
*/
Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
Sxpr x, y;
x = cons_new(k, v);
if(NOMEMP(x)) return x;
y = cons_new(x, l);
if(NOMEMP(y)) cons_free_cells(x);
return y;
}
/** Test if a list contains an element.
* Uses sxpr equality.
*
* @param l list
* @param x element to look for
* @return a tail of l with x as car, or ONULL
*/
Sxpr cons_member(Sxpr l, Sxpr x){
for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
return l;
}
/** Test if a list contains an element satisfying a test.
* The test function is called with v and an element of the list.
*
* @param l list
* @param test_fn test function to use
* @param v value for first argument to the test
* @return a tail of l with car satisfying the test, or 0
*/
Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
return l;
}
/** Test if the elements of list 't' are a subset of the elements
* of list 's'. Element order is not significant.
*
* @param s element list to check subset of
* @param t element list to check if is a subset
* @return 1 if is a subset, 0 otherwise
*/
int cons_subset(Sxpr s, Sxpr t){
for( ; CONSP(t); t = CDR(t)){
if(!CONSP(cons_member(s, CAR(t)))){
return 0;
}
}
return 1;
}
/** Test if two lists have equal sets of elements.
* Element order is not significant.
*
* @param s list to check
* @param t list to check
* @return 1 if equal, 0 otherwise
*/
int cons_set_equal(Sxpr s, Sxpr t){
return cons_subset(s, t) && cons_subset(t, s);
}
#ifdef USE_GC
/*============================================================================*/
/* The functions inside this ifdef are only safe if GC is used.
* Otherwise they may leak memory.
*/
/** Remove an element from a list (GC only).
* Uses sxpr equality and removes all instances, even
* if there are more than one.
*
* @param l list to remove elements from
* @param x element to remove
* @return modified input list
*/
Sxpr cons_remove(Sxpr l, Sxpr x){
return cons_remove_if(l, eq, x);
}
/** Remove elements satisfying a test (GC only).
* The test function is called with v and an element of the set.
*
* @param l list to remove elements from
* @param test_fn function to use to decide if an element should be removed
* @return modified input list
*/
Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
Sxpr prev = ONULL, elt, next;
for(elt = l; CONSP(elt); elt = next){
next = CDR(elt);
if(test_fn(v, CAR(elt))){
if(NULLP(prev)){
l = next;
} else {
CDR(prev) = next;
}
}
}
return l;
}
/** Set the value for a key in an alist (GC only).
* If the key is present, changes the value, otherwise
* adds a new cell.
*
* @param k key
* @param v value
* @param l alist
* @return modified or extended list
*/
Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
Sxpr e = assoc(k, l);
if(NULLP(e)){
l = acons(k, v, l);
} else {
CAR(CDR(e)) = v;
}
return l;
}
/*============================================================================*/
#endif /* USE_GC */
/** Create a new atom with the given name.
*
* @param name the name
* @return new atom
*/
Sxpr atom_new(char *name){
Sxpr n, obj = ONOMEM;
n = string_new(name);
if(NOMEMP(n)) goto exit;
obj = HALLOC(ObjAtom, T_ATOM);
if(NOMEMP(obj)) goto exit;
OBJ_ATOM(obj)->name = n;
exit:
return obj;
}
/** Free an atom.
*
* @param obj to free
*/
void atom_free(Sxpr obj){
// Interned atoms are shared, so do not free.
if(OBJ_ATOM(obj)->interned) return;
objfree(OBJ_ATOM(obj)->name);
hfree(obj);
}
/** Print an atom. Prints the atom name.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes printed
*/
int atom_print(IOStream *io, Sxpr obj, unsigned flags){
//return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
return string_print(io, OBJ_ATOM(obj)->name, flags);
}
/** Atom equality.
*
* @param x to compare
* @param y to compare
* @return 1 if equal, 0 otherwise
*/
int atom_equal(Sxpr x, Sxpr y){
int ok;
ok = eq(x, y);
if(ok) goto exit;
ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
if(ok) goto exit;
ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
exit:
return ok;
}
/** Get the name of an atom.
*
* @param obj atom
* @return name
*/
char * atom_name(Sxpr obj){
return string_string(OBJ_ATOM(obj)->name);
}
/** Get the C string from a string sxpr.
*
* @param obj string sxpr
* @return string
*/
char * string_string(Sxpr obj){
return OBJ_STRING(obj);
}
/** Get the length of a string.
*
* @param obj string
* @return length
*/
int string_length(Sxpr obj){
return strlen(OBJ_STRING(obj));
}
/** Create a new string. The input string is copied,
* and must be null-terminated.
*
* @param s characters to put in the string
* @return new sxpr
*/
Sxpr string_new(char *s){
int n = (s ? strlen(s) : 0);
Sxpr obj;
obj = halloc(n+1, T_STRING);
if(!NOMEMP(obj)){
char *str = OBJ_STRING(obj);
strncpy(str, s, n);
str[n] = '\0';
}
return obj;
}
/** Free a string.
*
* @param obj to free
*/
void string_free(Sxpr obj){
hfree(obj);
}
/** Determine if a string needs escapes when printed
* using the given flags.
*
* @param str string to check
* @param flags print flags
* @return 1 if needs escapes, 0 otherwise
*/
int needs_escapes(char *str, unsigned flags){
char *c;
int val = 0;
if(str){
for(c=str; *c; c++){
if(in_alpha_class(*c)) continue;
if(in_decimal_digit_class(*c)) continue;
if(in_class(*c, "/._+:@~-")) continue;
val = 1;
break;
}
}
//printf("\n> val=%d str=|%s|\n", val, str);
return val;
}
/** Print a string to a stream, with escapes if necessary.
*
* @param io stream to print to
* @param str string
* @param flags print flags
* @return number of bytes written
*/
int _string_print(IOStream *io, char *str, unsigned flags){
int k = 0;
if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
k += IOStream_print(io, str);
} else {
k += IOStream_print(io, "\"");
if(str){
char *s;
for(s = str; *s; s++){
if(*s < ' ' || *s >= 127 ){
switch(*s){
case '\a': k += IOStream_print(io, "\\a"); break;
case '\b': k += IOStream_print(io, "\\b"); break;
case '\f': k += IOStream_print(io, "\\f"); break;
case '\n': k += IOStream_print(io, "\\n"); break;
case '\r': k += IOStream_print(io, "\\r"); break;
case '\t': k += IOStream_print(io, "\\t"); break;
case '\v': k += IOStream_print(io, "\\v"); break;
default:
// Octal escape;
k += IOStream_print(io, "\\%o", *s);
break;
}
} else if(*s == c_double_quote ||
*s == c_single_quote ||
*s == c_escape){
k += IOStream_print(io, "\\%c", *s);
} else {
k+= IOStream_print(io, "%c", *s);
}
}
}
k += IOStream_print(io, "\"");
}
return k;
}
/** Print a string to a stream, with escapes if necessary.
*
* @param io stream to print to
* @param obj string
* @param flags print flags
* @return number of bytes written
*/
int string_print(IOStream *io, Sxpr obj, unsigned flags){
return _string_print(io, OBJ_STRING(obj), flags);
}
/** Compare an sxpr with a string for equality.
*
* @param x string to compare with
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int string_equal(Sxpr x, Sxpr y){
int ok = 0;
ok = eq(x,y);
if(ok) goto exit;
ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
if(ok) goto exit;
ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
exit:
return ok;
}
/** Create a new cons cell.
* The cell is ONOMEM if either argument is.
*
* @param car sxpr for the car
* @param cdr sxpr for the cdr
* @return new cons
*/
Sxpr cons_new(Sxpr car, Sxpr cdr){
Sxpr obj;
if(NOMEMP(car) || NOMEMP(cdr)){
obj = ONOMEM;
} else {
obj = HALLOC(ObjCons, T_CONS);
if(!NOMEMP(obj)){
ObjCons *z = OBJ_CONS(obj);
z->car = car;
z->cdr = cdr;
}
}
return obj;
}
/** Push a new element onto a list.
*
* @param list list to add to
* @param elt element to add
* @return 0 if successful, error code otherwise
*/
int cons_push(Sxpr *list, Sxpr elt){
Sxpr l;
l = cons_new(elt, *list);
if(NOMEMP(l)) return -ENOMEM;
*list = l;
return 0;
}
/** Free a cons. Recursively frees the car and cdr.
*
* @param obj to free
*/
void cons_free(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
next = CDR(obj);
objfree(CAR(obj));
hfree(obj);
}
if(!NULLP(obj)){
objfree(obj);
}
}
/** Free a cons and its cdr cells, but not the car sxprs.
* Does nothing if called on something that is not a cons.
*
* @param obj to free
*/
void cons_free_cells(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
next = CDR(obj);
hfree(obj);
}
}
/** Print a cons.
* Prints the cons in list format if the cdrs are conses.
* uses pair (dot) format if the last cdr is not a cons (or null).
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
int cons_print(IOStream *io, Sxpr obj, unsigned flags){
int first = 1;
int k = 0;
k += IOStream_print(io, "(");
for( ; CONSP(obj) ; obj = CDR(obj)){
if(first){
first = 0;
} else {
k += IOStream_print(io, " ");
}
k += objprint(io, CAR(obj), flags);
}
if(!NULLP(obj)){
k += IOStream_print(io, " . ");
k += objprint(io, obj, flags);
}
k += IOStream_print(io, ")");
return (IOStream_error(io) ? -1 : k);
}
/** Compare a cons with another sxpr for equality.
* If y is a cons, compares the cars and cdrs recursively.
*
* @param x cons to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int cons_equal(Sxpr x, Sxpr y){
return CONSP(y) &&
objequal(CAR(x), CAR(y)) &&
objequal(CDR(x), CDR(y));
}
/** Return the length of a cons list.
*
* @param obj list
* @return length
*/
int cons_length(Sxpr obj){
int count = 0;
for( ; CONSP(obj); obj = CDR(obj)){
count++;
}
return count;
}
/** Destructively reverse a cons list in-place.
* If the argument is not a cons it is returned unchanged.
*
* @param l to reverse
* @return reversed list
*/
Sxpr nrev(Sxpr l){
if(CONSP(l)){
// Iterate down the cells in the list making the cdr of
// each cell point to the previous cell. The last cell
// is the head of the reversed list.
Sxpr prev = ONULL;
Sxpr cell = l;
Sxpr next;
while(1){
next = CDR(cell);
CDR(cell) = prev;
if(!CONSP(next)) break;
prev = cell;
cell = next;
}
l = cell;
}
return l;
}
/** Print the null sxpr.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int null_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "()");
}
/** Print the `unspecified' sxpr none.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int none_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "<none>");
}
/** Print an integer.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int int_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "%d", OBJ_INT(obj));
}
/** Print a boolean.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
}
int sxprp(Sxpr obj, Sxpr name){
return CONSP(obj) && objequal(CAR(obj), name);
}
/** Get the name of an element.
*
* @param obj element
* @return name
*/
Sxpr sxpr_name(Sxpr obj){
Sxpr val = ONONE;
if(CONSP(obj)){
val = CAR(obj);
} else if(STRINGP(obj) || ATOMP(obj)){
val = obj;
}
return val;
}
int sxpr_is(Sxpr obj, char *s){
if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
if(STRINGP(obj)) return !strcmp(string_string(obj), s);
return 0;
}
int sxpr_elementp(Sxpr obj, Sxpr name){
return CONSP(obj) && objequal(CAR(obj), name);
}
/** Get the attributes of an sxpr.
*
* @param obj sxpr
* @return attributes
*/
Sxpr sxpr_attributes(Sxpr obj){
Sxpr val = ONULL;
if(CONSP(obj)){
obj = CDR(obj);
if(CONSP(obj)){
obj = CAR(obj);
if(sxprp(obj, intern("@"))){
val = CDR(obj);
}
}
}
return val;
}
Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
Sxpr val = ONONE;
val = assoc(sxpr_attributes(obj), key);
if(CONSP(val) && CONSP(CDR(val))){
val = CADR(def);
} else {
val = def;
}
return val;
}
/** Get the children of an sxpr.
*
* @param obj sxpr
* @return children
*/
Sxpr sxpr_children(Sxpr obj){
Sxpr val = ONULL;
if(CONSP(obj)){
val = CDR(obj);
if(CONSP(val) && sxprp(CAR(val), intern("@"))){
val = CDR(val);
}
}
return val;
}
Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
Sxpr val = ONONE;
Sxpr l;
for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
if(sxprp(CAR(l), name)){
val = CAR(l);
break;
}
}
if(NONEP(val)) val = def;
return val;
}
Sxpr sxpr_child0(Sxpr obj, Sxpr def){
Sxpr val = ONONE;
Sxpr l = sxpr_children(obj);
if(CONSP(l)){
val = CAR(l);
} else {
val = def;
}
return val;
}
Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
Sxpr val = ONONE;
val = sxpr_child(obj, name, ONONE);
if(NONEP(val)){
val = def;
} else {
val = sxpr_child0(val, def);
}
return val;
}
/** Table of interned symbols. Indexed by symbol name. */
static HashTable *symbols = NULL;
/** Hash function for entries in the symbol table.
*
* @param key to hash
* @return hashcode
*/
static Hashcode sym_hash_fn(void *key){
return hash_string((char*)key);
}
/** Key equality function for the symbol table.
*
* @param x to compare
* @param y to compare
* @return 1 if equal, 0 otherwise
*/
static int sym_equal_fn(void *x, void *y){
return !strcmp((char*)x, (char*)y);
}
/** Entry free function for the symbol table.
*
* @param table the entry is in
* @param entry being freed
*/
static void sym_free_fn(HashTable *table, HTEntry *entry){
if(entry){
objfree(((ObjAtom*)entry->value)->name);
HTEntry_free(entry);
}
}
/** Initialize the symbol table.
*
* @return 0 on sucess, error code otherwise
*/
static int init_symbols(void){
symbols = HashTable_new(100);
if(symbols){
symbols->key_hash_fn = sym_hash_fn;
symbols->key_equal_fn = sym_equal_fn;
symbols->entry_free_fn = sym_free_fn;
return 0;
}
return -1;
}
/** Cleanup the symbol table. Frees the table and all its symbols.
*/
void cleanup_symbols(void){
HashTable_free(symbols);
symbols = NULL;
}
/** Get the interned symbol with the given name.
* No new symbol is created.
*
* @return symbol or null
*/
Sxpr get_symbol(char *sym){
HTEntry *entry;
if(!symbols){
if(init_symbols()) return ONOMEM;
return ONULL;
}
entry = HashTable_get_entry(symbols, sym);
if(entry){
return OBJP(T_ATOM, entry->value);
} else {
return ONULL;
}
}
/** Get the interned symbol with the given name.
* Creates a new symbol if necessary.
*
* @return symbol
*/
Sxpr intern(char *sym){
Sxpr symbol = get_symbol(sym);
if(NULLP(symbol)){
if(!symbols) return ONOMEM;
symbol = atom_new(sym);
if(!NOMEMP(symbol)){
OBJ_ATOM(symbol)->interned = TRUE;
HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
}
}
return symbol;
}
+413
View File
@@ -0,0 +1,413 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SXPR_H_
#define _XEN_LIB_SXPR_H_
#include <stdint.h>
#include "hash_table.h"
#include "iostream.h"
#include "allocate.h"
/** @file
* Definitions for rules and sxprs.
*/
#ifndef NULL
#define NULL 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/** Sxpr type. */
typedef int16_t TypeCode;
/** A typed sxpr handle.*/
typedef struct Sxpr {
/** Sxpr type. */
TypeCode type;
union {
/** Sxpr value. */
unsigned long ul;
/** Pointer. */
void *ptr;
} v;
} Sxpr;
/** Sxpr type to indicate out of memory. */
#define T_NOMEM ((TypeCode)-1)
/** The 'unspecified' sxpr. */
#define T_NONE ((TypeCode)0)
/** The empty list. */
#define T_NULL ((TypeCode)1)
/** Unsigned integer. */
#define T_UINT ((TypeCode)2)
/** A string. */
#define T_STRING ((TypeCode)3)
/** An atom. */
#define T_ATOM ((TypeCode)4)
/** A boolean. */
#define T_BOOL ((TypeCode)5)
/** A cons (pair or list). */
#define T_CONS ((TypeCode)10)
/** An error. */
#define T_ERR ((TypeCode)40)
/** An atom. */
typedef struct ObjAtom {
Sxpr name;
Hashcode hashcode;
int interned;
} ObjAtom;
/** A cons (pair). */
typedef struct ObjCons {
Sxpr car;
Sxpr cdr;
} ObjCons;
/** A vector. */
typedef struct ObjVector {
int n;
Sxpr data[0];
} ObjVector;
/** Flags for sxpr printing. */
enum PrintFlags {
PRINT_RAW = 0x001,
PRINT_TYPE = 0x002,
PRINT_PRETTY = 0x004,
PRINT_NUM = 0x008,
};
/** An integer sxpr.
*
* @param ty type
* @param val integer value
*/
#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
/** A pointer sxpr.
* If the pointer is non-null, returns an sxpr containing it.
* If the pointer is null, returns ONOMEM.
*
* @param ty type
* @param val pointer
*/
#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
/** Make an integer sxpr containing a pointer.
*
* @param val pointer
*/
#define PTR(val) OBJP(T_UINT, (void*)(val))
/** Make an integer sxpr.
* @param x value
*/
#define OINT(x) OBJI(T_UINT, x)
/** Make an error sxpr.
*
* @param x value
*/
#define OERR(x) OBJI(T_ERR, x)
/** Out of memory constant. */
#define ONOMEM OBJI(T_NOMEM, 0)
/** The `unspecified' constant. */
#define ONONE OBJI(T_NONE, 0)
/** Empty list constant. */
#define ONULL OBJI(T_NULL, 0)
/** False constant. */
#define OFALSE OBJI(T_BOOL, 0)
/** True constant. */
#define OTRUE OBJI(T_BOOL, 1)
/* Recognizers for the various sxpr types. */
#define ATOMP(obj) has_type(obj, T_ATOM)
#define BOOLP(obj) has_type(obj, T_BOOL)
#define CONSP(obj) has_type(obj, T_CONS)
#define ERRP(obj) has_type(obj, T_ERR)
#define INTP(obj) has_type(obj, T_UINT)
#define NOMEMP(obj) has_type(obj, T_NOMEM)
#define NONEP(obj) has_type(obj, T_NONE)
#define NULLP(obj) has_type(obj, T_NULL)
#define STRINGP(obj) has_type(obj, T_STRING)
#define TRUEP(obj) get_ul(obj)
/** Convert an sxpr to an unsigned integer. */
#define OBJ_UINT(x) get_ul(x)
/** Convert an sxpr to an integer. */
#define OBJ_INT(x) (int)get_ul(x)
/* Conversions of sxprs to their values.
* No checking is done.
*/
#define OBJ_STRING(x) ((char*)get_ptr(x))
#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
#define CAR(x) (OBJ_CONS(x)->car)
#define CDR(x) (OBJ_CONS(x)->cdr)
#define CAAR(x) (CAR(CAR(x)))
#define CADR(x) (CAR(CDR(x)))
#define CDAR(x) (CDR(CAR(x)))
#define CDDR(x) (CDR(CDR(x)))
/** Get the integer value from an sxpr.
*
* @param obj sxpr
* @return value
*/
static inline unsigned long get_ul(Sxpr obj){
return obj.v.ul;
}
/** Get the pointer value from an sxpr.
*
* @param obj sxpr
* @return value
*/
static inline void * get_ptr(Sxpr obj){
return obj.v.ptr;
}
/** Create an sxpr containing a pointer.
*
* @param type typecode
* @param val pointer
* @return sxpr
*/
static inline Sxpr obj_ptr(TypeCode type, void *val){
return (Sxpr){ type: type, v: { ptr: val } };
}
/** Create an sxpr containing an integer.
*
* @param type typecode
* @param val integer
* @return sxpr
*/
static inline Sxpr obj_ul(TypeCode type, unsigned long val){
return (Sxpr){ type: type, v: { ul: val } };
}
/** Get the type of an sxpr.
*
* @param obj sxpr
* @return type
*/
static inline TypeCode get_type(Sxpr obj){
return obj.type;
}
/** Check the type of an sxpr.
*
* @param obj sxpr
* @param type to check
* @return 1 if has the type, 0 otherwise
*/
static inline int has_type(Sxpr obj, TypeCode type){
return get_type(obj) == type;
}
/** Compare sxprs for literal equality of type and value.
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
static inline int eq(Sxpr x, Sxpr y){
return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
}
/** Checked version of CAR
*
* @param x sxpr
* @return CAR if a cons, x otherwise
*/
static inline Sxpr car(Sxpr x){
return (CONSP(x) ? CAR(x) : x);
}
/** Checked version of CDR.
*
* @param x sxpr
* @return CDR if a cons, null otherwise
*/
static inline Sxpr cdr(Sxpr x){
return (CONSP(x) ? CDR(x) : ONULL);
}
/** Allocate some memory and return an sxpr containing it.
* Returns ONOMEM if allocation failed.
*
* @param n number of bytes to allocate
* @param ty typecode
* @return sxpr
*/
static inline Sxpr halloc(size_t n, TypeCode ty){
return OBJP(ty, allocate(n));
}
/** Allocate an sxpr containing a pointer to the given type.
*
* @param ty type (uses sizeof to determine how many bytes to allocate)
* @param code typecode
* @return sxpr, ONOMEM if allocation failed
*/
#define HALLOC(ty, code) halloc(sizeof(ty), code)
typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
typedef int ObjEqualFn(Sxpr obj, Sxpr other);
typedef void ObjFreeFn(Sxpr obj);
/** An sxpr type definition. */
typedef struct SxprType {
TypeCode type;
char *name;
int pointer;
ObjPrintFn *print;
ObjEqualFn *equal;
ObjFreeFn *free;
} SxprType;
extern SxprType *get_sxpr_type(int ty);
/** Free the pointer in an sxpr.
*
* @param x sxpr containing a pointer
*/
static inline void hfree(Sxpr x){
deallocate(get_ptr(x));
}
extern int objprint(IOStream *io, Sxpr x, unsigned flags);
extern int objequal(Sxpr x, Sxpr y);
extern void objfree(Sxpr x);
extern void cons_free_cells(Sxpr obj);
extern Sxpr intern(char *s);
extern Sxpr assoc(Sxpr k, Sxpr l);
extern Sxpr assocq(Sxpr k, Sxpr l);
extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
extern Sxpr nrev(Sxpr l);
extern Sxpr cons_member(Sxpr l, Sxpr x);
extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
extern int cons_subset(Sxpr s, Sxpr t);
extern int cons_set_equal(Sxpr s, Sxpr t);
#ifdef USE_GC
extern Sxpr cons_remove(Sxpr l, Sxpr x);
extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
#endif
extern Sxpr atom_new(char *name);
extern char * atom_name(Sxpr obj);
extern Sxpr string_new(char *s);
extern char * string_string(Sxpr obj);
extern int string_length(Sxpr obj);
extern Sxpr cons_new(Sxpr car, Sxpr cdr);
extern int cons_push(Sxpr *list, Sxpr elt);
extern int cons_length(Sxpr obj);
Sxpr sxpr_name(Sxpr obj);
int sxpr_is(Sxpr obj, char *s);
int sxpr_elementp(Sxpr obj, Sxpr name);
Sxpr sxpr_attributes(Sxpr obj);
Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
Sxpr sxpr_children(Sxpr obj);
Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
Sxpr sxpr_child0(Sxpr obj, Sxpr def);
Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
/** Create a new atom.
*
* @param s atom name
* @return new atom
*/
static inline Sxpr mkatom(char *s){
return atom_new(s);
}
/** Create a new string sxpr.
*
* @param s string bytes (copied)
* @return new string
*/
static inline Sxpr mkstring(char *s){
return string_new(s);
}
/** Create an integer sxpr.
*
* @param i value
* @return sxpr
*/
static inline Sxpr mkint(int i){
return OBJI(T_UINT, i);
}
/** Create a boolean sxpr.
*
* @param b value
* @return sxpr
*/
static inline Sxpr mkbool(int b){
return OBJI(T_BOOL, (b ? 1 : 0));
}
/* Constants used in parsing and printing. */
#define k_list_open "("
#define c_list_open '('
#define k_list_close ")"
#define c_list_close ')'
#define k_true "true"
#define k_false "false"
#define c_var '$'
#define c_escape '\\'
#define c_single_quote '\''
#define c_double_quote '"'
#define c_string_open c_double_quote
#define c_string_close c_double_quote
#define c_data_open '['
#define c_data_close ']'
#define c_binary '*'
#define c_eval '!'
#define c_concat_open '{'
#define c_concat_close '}'
#endif /* ! _XEN_LIB_SXPR_H_ */
+897
View File
@@ -0,0 +1,897 @@
#ifdef __KERNEL__
# include <linux/config.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
#else
# include <stdlib.h>
# include <errno.h>
#endif
#include "iostream.h"
#include "lexis.h"
#include "sxpr_parser.h"
#include "sys_string.h"
/** @file
* Sxpr parsing.
*
* So that the parser does not leak memory, all sxprs constructed by
* the parser must be freed on error. On successful parse the sxpr
* returned becomes the responsibility of the caller.
*
* @author Mike Wray <mike.wray@hpl.hp.com>
*/
#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
static void reset(Parser *z);
static int inputchar(Parser *p, char c);
static int savechar(Parser *p, char c);
extern void parse_error(Parser *in);
extern void parse_error_id(Parser *in, ParseErrorId id);
static int begin_start(Parser *p, char c);
static int state_start(Parser *p, char c);
static int end_start(Parser *p);
static int begin_comment(Parser *p, char c);
static int state_comment(Parser *p, char c);
static int end_comment(Parser *p);
static int begin_string(Parser *p, char c);
static int state_string(Parser *p, char c);
static int end_string(Parser *p);
static int state_escape(Parser *p, char c);
static int state_octal(Parser *p, char c);
static int state_hex(Parser *p, char c);
static int begin_atom(Parser *p, char c);
static int state_atom(Parser *p, char c);
static int end_atom(Parser *p);
static int state_list(Parser *p, char c);
static int begin_list(Parser *p, char c);
static int end_list(Parser *p);
/** Print a parse error.
*
* @param in parser
* @param msg format followed by printf arguments
*/
void eprintf(Parser *in, char *msg, ...){
va_list args;
if(in->error_out){
va_start(args, msg);
IOStream_vprint(in->error_out, msg, args);
va_end(args);
}
}
/** Print a parse warning.
*
* @param in parser
* @param msg format followed by printf arguments
*/
void wprintf(Parser *in, char *msg, ...){
va_list args;
if(in->error_out){
va_start(args, msg);
IOStream_vprint(in->error_out, msg, args);
va_end(args);
}
}
/*============================================================================*/
/** Record defining the message for a parse error. */
typedef struct {
ParseErrorId id;
char *message;
} ParseError;
/** Format for printing parse error messages. */
#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
/** Message catalog for the parse error codes. */
static ParseError catalog[] = {
{ PARSE_ERR_UNSPECIFIED, "unspecified error" },
{ PARSE_ERR_NOMEM, "out of memory" },
{ PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
{ PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
{ PARSE_ERR_INVALID_SYNTAX, "syntax error" },
{ PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
{ 0, NULL }
};
/** Number of entries in the message catalog. */
const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
void ParserState_free(ParserState *z){
if(!z) return;
objfree(z->val);
deallocate(z);
}
int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){
int err = 0;
ParserState *z;
z = ALLOCATE(ParserState);
if(z){
z->fn = fn;
z->parent = parent;
z->val = ONULL;
} else {
err = -ENOMEM;
}
if(!err) *val = z;
return err;
}
/** Free a parser.
* No-op if the parser is null.
*
* @param z parser
*/
void Parser_free(Parser *z){
if(!z) return;
objfree(z->val);
z->val = ONONE;
deallocate(z);
}
/** Create a new parser. The error stream defaults to null.
*/
Parser * Parser_new(void){
Parser *z = ALLOCATE(Parser);
int err = -ENOMEM;
if(!z) goto exit;
err = 0;
reset(z);
exit:
if(err){
Parser_free(z);
z = NULL;
}
return z;
}
/** Get the next character.
* Records the character read in the parser,
* and sets the line and character counts.
*
* @param p parser
* @return error flag: 0 on success, non-zero on error
*/
static int inputchar(Parser *p, char c){
int err = 0;
if(c=='\n'){
p->line_no++;
p->char_no = 0;
} else {
p->char_no++;
}
return err;
}
static int savechar(Parser *p, char c){
int err = 0;
if(p->buf_i >= p->buf_n){
err = -ENOMEM;
goto exit;
}
p->buf[p->buf_i] = c;
p->buf_i++;
exit:
return err;
}
int Parser_input_char(Parser *p, char c){
int err = 0;
if(at_eof(p)){
//skip;
} else {
inputchar(p, c);
}
if(!p->state){
err = begin_start(p, c);
if(err) goto exit;
}
err = p->state->fn(p, c);
exit:
return err;
}
int Parser_input_eof(Parser *p){
int err = 0;
p->eof = 1;
err = Parser_input_char(p, IOSTREAM_EOF);
return err;
}
int Parser_input(Parser *p, char *buf, int buf_n){
int err = 0;
int i = 0;
if(buf_n <= 0){
err = Parser_input_eof(p);
goto exit;
}
for(i = 0; i<buf_n; i++){
err = Parser_input_char(p, buf[i]);
if(err) goto exit;
}
exit:
err = (err < 0 ? err : buf_n);
return err;
}
int Parser_push(Parser *p, ParserStateFn *fn){
int err = 0;
err = ParserState_new(fn, p->state, &p->state);
return err;
}
int Parser_pop(Parser *p){
int err = 0;
ParserState *s = p->state;
p->state = s->parent;
ParserState_free(s);
return err;
}
int Parser_return(Parser *p){
int err = 0;
Sxpr val = ONONE;
if(!p->state){
err = -EINVAL;
goto exit;
}
val = p->state->val;
p->state->val = ONONE;
err = Parser_pop(p);
if(err) goto exit;
if(p->state){
err = cons_push(&p->state->val, val);
} else {
val = nrev(val);
p->val = val;
}
exit:
if(err){
objfree(val);
}
return err;
}
/** Determine if a character is a separator.
*
* @param p parser
* @param c character to test
* @return 1 if a separator, 0 otherwise
*/
static int is_separator(Parser *p, char c){
return in_sep_class(c);
}
/** Return the current token.
* The return value points at the internal buffer, so
* it must not be modified (or freed). Use copy_token() if you need a copy.
*
* @param p parser
* @return token
*/
char *peek_token(Parser *p){
return p->buf;
}
/** Return a copy of the current token.
* The returned value should be freed when finished with.
*
* @param p parser
* @return copy of token
*/
char *copy_token(Parser *p){
return strdup(peek_token(p));
}
static int do_intern(Parser *p){
int err = 0;
Sxpr obj = intern(peek_token(p));
if(NOMEMP(obj)){
err = -ENOMEM;
} else {
p->state->val = obj;
}
return err;
}
static int do_string(Parser *p){
int err = 0;
Sxpr obj;
obj = string_new(peek_token(p));
if(NOMEMP(obj)){
err = -ENOMEM;
} else {
p->state->val = obj;
}
return err;
}
void newtoken(Parser *p){
memset(p->buf, 0, p->buf_n);
p->buf_i = 0;
p->tok_begin_line = p->line_no;
p->tok_begin_char = p->char_no;
}
int get_escape(char c, char *d){
int err = 0;
switch(c){
case 'a': *d = '\a'; break;
case 'b': *d = '\b'; break;
case 'f': *d = '\f'; break;
case 'n': *d = '\n'; break;
case 'r': *d = '\r'; break;
case 't': *d = '\t'; break;
case 'v': *d = '\v'; break;
case c_escape: *d = c_escape; break;
case c_single_quote: *d = c_single_quote; break;
case c_double_quote: *d = c_double_quote; break;
default:
err = -EINVAL;
}
return err;
}
int begin_start(Parser *p, char c){
return Parser_push(p, state_start);
}
int state_start(Parser *p, char c){
int err = 0;
if(at_eof(p)){
err = end_start(p);
} else if(in_space_class(c)){
//skip
} else if(in_comment_class(c)){
begin_comment(p, c);
} else if(c == c_list_open){
begin_list(p, c);
} else if(c == c_list_close){
parse_error(p);
err = -EINVAL;
} else if(in_string_quote_class(c)){
begin_string(p, c);
} else if(in_printable_class(c)){
begin_atom(p, c);
} else if(c == 0x04){
//ctrl-D, EOT: end-of-text.
Parser_input_eof(p);
} else {
parse_error(p);
err = -EINVAL;
}
return err;
}
int end_start(Parser *p){
int err = 0;
err = Parser_return(p);
return err;
}
int begin_comment(Parser *p, char c){
int err = 0;
err = Parser_push(p, state_comment);
if(err) goto exit;
err = inputchar(p, c);
exit:
return err;
}
int state_comment(Parser *p, char c){
int err = 0;
if(c == '\n' || at_eof(p)){
err = end_comment(p);
} else {
err = inputchar(p, c);
}
return err;
}
int end_comment(Parser *p){
return Parser_pop(p);
}
int begin_string(Parser *p, char c){
int err = 0;
err = Parser_push(p, state_string);
if(err) goto exit;
newtoken(p);
p->state->delim = c;
exit:
return err;
}
int state_string(Parser *p, char c){
int err = 0;
if(at_eof(p)){
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
err = -EINVAL;
} else if(c == p->state->delim){
err = end_string(p);
} else if(c == '\\'){
err = Parser_push(p, state_escape);
} else {
err = savechar(p, c);
}
return err;
}
int end_string(Parser *p){
int err = 0;
err = do_string(p);
if(err) goto exit;
err = Parser_return(p);
exit:
return err;
}
int state_escape(Parser *p, char c){
int err = 0;
char d;
if(at_eof(p)){
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
err = -EINVAL;
goto exit;
}
if(get_escape(c, &d) == 0){
err = savechar(p, d);
if(err) goto exit;
err = Parser_pop(p);
} else if(c == 'x'){
p->state->fn = state_hex;
p->state->ival = 0;
p->state->count = 0;
} else {
p->state->fn = state_octal;
p->state->ival = 0;
p->state->count = 0;
err = Parser_input_char(p, c);
}
exit:
return err;
}
int octaldone(Parser *p){
int err = 0;
char d = (char)(p->state->ival & 0xff);
err = Parser_pop(p);
if(err) goto exit;
err = Parser_input_char(p, d);
exit:
return err;
}
int octaldigit(Parser *p, char c){
int err = 0;
p->state->ival *= 8;
p->state->ival += c - '0';
p->state->count++;
if(err) goto exit;
if(p->state->ival < 0 || p->state->ival > 0xff){
parse_error(p);
err = -EINVAL;
goto exit;
}
if(p->state->count == 3){
err = octaldone(p);
}
exit:
return err;
}
int state_octal(Parser *p, char c){
int err = 0;
if(at_eof(p)){
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
err = -EINVAL;
goto exit;
} else if('0' <= c && c <= '7'){
err = octaldigit(p, c);
} else {
err = octaldone(p);
if(err) goto exit;
Parser_input_char(p, c);
}
exit:
return err;
}
int hexdone(Parser *p){
int err = 0;
char d = (char)(p->state->ival & 0xff);
err = Parser_pop(p);
if(err) goto exit;
err = Parser_input_char(p, d);
exit:
return err;
}
int hexdigit(Parser *p, char c, char d){
int err = 0;
p->state->ival *= 16;
p->state->ival += c - d;
p->state->count++;
if(err) goto exit;
if(p->state->ival < 0 || p->state->ival > 0xff){
parse_error(p);
err = -EINVAL;
goto exit;
}
if(p->state->count == 2){
err = hexdone(p);
}
exit:
return err;
}
int state_hex(Parser *p, char c){
int err = 0;
if(at_eof(p)){
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
err = -EINVAL;
goto exit;
} else if('0' <= c && c <= '9'){
err = hexdigit(p, c, '0');
} else if('A' <= c && c <= 'F'){
err = hexdigit(p, c, 'A');
} else if('a' <= c && c <= 'f'){
err = hexdigit(p, c, 'a');
} else if(p->state->count){
err =hexdone(p);
if(err) goto exit;
Parser_input_char(p, c);
}
exit:
return err;
}
int begin_atom(Parser *p, char c){
int err = 0;
err = Parser_push(p, state_atom);
if(err) goto exit;
newtoken(p);
err = savechar(p, c);
exit:
return err;
}
int state_atom(Parser *p, char c){
int err = 0;
if(at_eof(p)){
err = end_atom(p);
} else if(is_separator(p, c) ||
in_space_class(c) ||
in_comment_class(c)){
err = end_atom(p);
if(err) goto exit;
err = Parser_input_char(p, c);
} else {
err = savechar(p, c);
}
exit:
return err;
}
int end_atom(Parser *p){
int err = 0;
err = do_intern(p);
if(err) goto exit;
err = Parser_return(p);
exit:
return err;
}
int state_list(Parser *p, char c){
int err = 0;
if(at_eof(p)){
parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
err = -EINVAL;
} else if(c == c_list_close){
p->state->val = nrev(p->state->val);
err = end_list(p);
} else {
err = state_start(p, c);
}
return err;
}
int begin_list(Parser *p, char c){
return Parser_push(p, state_list);
}
int end_list(Parser *p){
return Parser_return(p);
}
/** Reset the fields of a parser to initial values.
*
* @param z parser
*/
static void reset(Parser *z){
IOStream *error_out = z->error_out;
int flags = z->flags;
zero(z, sizeof(Parser));
z->buf_n = sizeof(z->buf) - 1;
z->buf_i = 0;
z->line_no = 1;
z->char_no = 0;
z->error_out = error_out;
z->flags = flags;
}
/** Set the parser error stream.
* Parse errors are reported on the the error stream if it is non-null.
*
* @param z parser
* @param error_out error stream
*/
void set_error_stream(Parser *z, IOStream *error_out){
if(z){
z->error_out = error_out;
}
}
/** Get the parser error message for an error code.
*
* @param id error code
* @return error message (empty string if the code is unknown)
*/
static char *get_message(ParseErrorId id){
int i;
for(i=0; i<catalog_n; i++){
if(id == catalog[i].id){
return catalog[i].message;
}
}
return "";
}
/** Get the line number.
*
* @param in parser
*/
int get_line(Parser *in){
return in->line_no;
}
/** Get the column number.
*
* @param in parser
*/
int get_column(Parser *in){
return in->char_no;
}
/** Get the line number the current token started on.
*
* @param in parser
*/
int get_tok_line(Parser *in){
return in->tok_begin_line;
}
/** Get the column number the current token started on.
*
* @param in parser
*/
int get_tok_column(Parser *in){
return in->tok_begin_char;
}
/** Report a parse error.
* Does nothing if the error stream is null or there is no error.
*
* @param in parser
*/
static void report_error(Parser *in){
if(in->error_out && in->err){
char *msg = get_message(in->err);
char *tok = peek_token(in);
IOStream_print(in->error_out, PARSE_ERR_FMT,
get_tok_line(in), get_tok_column(in), msg);
if(tok && tok[0]){
IOStream_print(in->error_out, " '%s'", tok);
}
IOStream_print(in->error_out, "\n");
}
}
/** Get the error message for the current parse error code.
* Does nothing if there is no error.
*
* @param in parser
* @param buf where to place the message
* @param n maximum number of characters to place in buf
* @return current error code (zero for no error)
*/
int parse_error_message(Parser *in, char *buf, int n){
if(in->err){
char *msg = get_message(in->err);
snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
}
return in->err;
}
/** Flag an unspecified parse error. All subsequent reads will fail.
*
* @param in parser
*/
void parse_error(Parser *in){
parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
}
/** Flag a parse error. All subsequent reads will fail.
* Does not change the parser error code if it is already set.
*
* @param in parser
* @param id error code
*/
void parse_error_id(Parser *in, ParseErrorId id){
if(!in->err){
in->err = id;
report_error(in);
}
}
/** Test if the parser's error flag is set.
*
* @param in parser
* @return 1 if set, 0 otherwise
*/
int has_error(Parser *in){
return (in->err > 0);
}
/** Test if the parser is at end of input.
*
* @param in parser
* @return 1 if at EOF, 0 otherwise
*/
int at_eof(Parser *p){
return p->eof;
}
#ifdef SXPR_PARSER_MAIN
/* Stuff for standalone testing. */
#include "file_stream.h"
#include "string_stream.h"
int stringof(Sxpr exp, char **s){
int err = 0;
if(ATOMP(exp)){
*s = atom_name(exp);
} else if(STRINGP(exp)){
*s = string_string(exp);
} else {
err = -EINVAL;
*s = NULL;
}
return err;
}
int child_string(Sxpr exp, Sxpr key, char **s){
int err = 0;
Sxpr val = sxpr_child_value(exp, key, ONONE);
err = stringof(val, s);
return err;
}
int intof(Sxpr exp, int *v){
int err = 0;
char *s;
unsigned long l;
if(INTP(exp)){
*v = OBJ_INT(exp);
} else {
err = stringof(exp, &s);
if(err) goto exit;
err = convert_atoul(s, &l);
*v = (int)l;
}
exit:
return err;
}
int child_int(Sxpr exp, Sxpr key, int *v){
int err = 0;
Sxpr val = sxpr_child_value(exp, key, ONONE);
err = intof(val, v);
return err;
}
int eval_vnet(Sxpr exp){
int err = 0;
Sxpr oid = intern("id");
int id;
err = child_int(exp, oid, &id);
if(err) goto exit;
dprintf("> vnet id=%d\n", id);
exit:
dprintf("< err=%d\n", err);
return err;
}
int eval_connect(Sxpr exp){
int err = 0;
Sxpr ovif = intern("vif");
Sxpr ovnet = intern("vnet");
char *vif;
int vnet;
err = child_string(exp, ovif, &vif);
if(err) goto exit;
err = child_int(exp, ovnet, &vnet);
if(err) goto exit;
dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
exit:
dprintf("< err=%d\n", err);
return err;
}
int eval(Sxpr exp){
int err = 0;
Sxpr oconnect = intern("connect");
Sxpr ovnet = intern("vnet");
if(sxpr_elementp(exp, ovnet)){
err = eval_vnet(exp);
} else if(sxpr_elementp(exp, oconnect)){
err = eval_connect(exp);
} else {
err = -EINVAL;
}
return err;
}
/** Main program for testing.
* Parses input and prints it.
*
* @param argc number of arguments
* @param argv arguments
* @return error code
*/
int main(int argc, char *argv[]){
Parser *pin;
int err = 0;
char buf[1024];
int k;
Sxpr obj, l, x;
pin = Parser_new();
set_error_stream(pin, iostdout);
dprintf("> parse...\n");
while(1){
k = fread(buf, 1, 1024, stdin);
err = Parser_input(pin, buf, k);
dprintf("> Parser_input=%d\n", err);
if(k <= 0) break;
}
obj = pin->val;
for(l = obj ; CONSP(l); l = CDR(l)){
x = CAR(l);
objprint(iostdout, x, 0); printf("\n");
eval(x);
}
dprintf("> err=%d\n", err);
return 0;
}
#endif
+125
View File
@@ -0,0 +1,125 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SXPR_PARSER_H_
#define _XEN_LIB_SXPR_PARSER_H_
#include "sxpr.h"
#include "iostream.h"
/** @file
* Sxpr parsing definitions.
*/
/** Size of a parser input buffer.
* Tokens read must fit into this size (including trailing null).
*/
#define PARSER_BUF_SIZE 1024
struct Parser;
typedef int ParserStateFn(struct Parser *, char c);
typedef struct ParserState {
struct ParserState *parent;
Sxpr val;
int ival;
int count;
char delim;
ParserStateFn *fn;
} ParserState;
/** Structure representing an input source for the parser.
* Can read from any IOStream implementation.
*/
typedef struct Parser {
Sxpr val;
/** Error reporting stream (null for no reports). */
IOStream *error_out;
int eof;
/** Error flag. Non-zero if there has been a read error. */
int err;
/** Line number on input (from 1). */
int line_no;
/** Column number of input (reset on new line). */
int char_no;
/** Lookahead character. */
char c;
/** Buffer for reading tokens. */
char buf[PARSER_BUF_SIZE];
/** Size of token buffer. */
int buf_n;
int buf_i;
/** Line the last token started on. */
int tok_begin_line;
/** Character number the last token started on. */
int tok_begin_char;
/** Parsing flags. */
int flags;
ParserState *state;
} Parser;
/** Parser error codes. */
typedef enum {
PARSE_ERR_NONE=0,
PARSE_ERR_UNSPECIFIED,
PARSE_ERR_NOMEM,
PARSE_ERR_UNEXPECTED_EOF,
PARSE_ERR_TOKEN_TOO_LONG,
PARSE_ERR_INVALID_SYNTAX,
PARSE_ERR_INVALID_ESCAPE,
} ParseErrorId;
/** Parser flags. */
//enum {
//};
/** Raise some parser flags.
*
* @param in parser
* @param flags flags mask
*/
inline static void parser_flags_raise(Parser *in, int flags){
in->flags |= flags;
}
/** Lower some parser flags.
*
* @param in parser
* @param flags flags mask
*/
inline static void parser_flags_lower(Parser *in, int flags){
in->flags &= ~flags;
}
/** Clear all parser flags.
*
* @param in parser
*/
inline static void parser_flags_clear(Parser *in){
in->flags = 0;
}
extern void Parser_free(Parser *z);
extern Parser * Parser_new(void);
extern int Parser_input(Parser *p, char *buf, int buf_n);
extern int Parser_input_eof(Parser *p);
extern int parse_error_message(Parser *in, char *buf, int n);
extern int has_error(Parser *in);
extern int at_eof(Parser *in);
#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */
+12
View File
@@ -0,0 +1,12 @@
#ifndef _XENO_SYS_CTYPE_H_
#define _XENO_SYS_CTYPE_H_
/** @file
** Replacement for ctype include that can be used
* from user or kernel code.
*/
#ifdef __KERNEL__
# include <linux/ctype.h>
#else
# include <ctype.h>
#endif
#endif /* ! _XENO_SYS_CTYPE_H_ */
+309
View File
@@ -0,0 +1,309 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library is
* distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sys_net.h"
#include "sys_string.h"
/** @file
* All network data are kept in network order and only converted to
* host order for display. Network data includes IP addresses, port numbers and
* network masks.
*/
/** Maximum value for a port. */
#define PORT_MAX 0xffff
/** Convert a number of bits to a network mask
* for IP addresses. The number of bits must
* be in the range 1-31.
*
* @param n number of bits to set in the mask
* @return value with n high bits set (in network order)
*/
unsigned long bits_to_mask(int n){
unsigned long mask = (n ? (1 << 31) : 0);
int i;
for(i=1; i<n; i++){
mask |= (mask >> 1);
}
return htonl(mask);
}
/** Convert a network mask to a number of bits.
*
* @param mask network mask in network order
* @return number of bits in mask
*/
int mask_to_bits(unsigned long mask){
// Start with n set to the number of bits in the mask. Then reduce n by
// the number of low zero bits in the mask.
int n = 32;
for(mask = ntohl(mask);
(mask & 1)==0 && n>0;
mask >>= 1){
n--;
}
return n;
}
/** Get the index of the first occurrence of a character in a string.
* Stops at end of string or after n characters.
*
* @param s input string
* @param n maximum number of charactes to search
* @param c character to look for
* @return index of first occurrence, -1 if not found
*/
inline static int indexof(const char *s, int n, char c){
int i;
for(i=0; i<n && *s; i++, s++){
if(*s == c) return i;
}
return -1;
}
/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
*
* @param s input string
* @param address where to put the address
* @return 0 on success, -1 on error
*/
int get_inet_addr(const char *s, unsigned long *address){
// Number of bits in a byte.
const int BYTE_BITS = 8;
// Number of bytes in a word.
const int WORD_BYTES = 4;
// Max value for a component of an address.
const int ADDR_MAX = 255;
// Separator for components of an address.
const char dot = '.';
int n;
unsigned long addr = 0;
unsigned long v;
int i;
int err = -1;
// Bit shift for the current byte.
int shift = BYTE_BITS * (WORD_BYTES - 1);
char buf[64];
n = strlen(s);
if(n >= sizeof(buf)){
goto exit;
}
for(i=0; i < WORD_BYTES; i++){
int idx = indexof(s, n, dot);
idx = (idx < 0 ? strlen(s) : idx);
strncpy(buf, s, idx); buf[idx]='\0';
if(convert_atoul(buf, &v)){
goto exit;
}
if(v < 0 || v > ADDR_MAX){
goto exit;
}
addr |= (v << shift);
if(idx == n) break;
shift -= BYTE_BITS;
s += idx+1;
}
err = 0;
exit:
addr = htonl(addr);
*address = (err ? 0 : addr);
return err;
}
#ifdef __KERNEL__
/** Convert an address in network order to IPv4 dot notation.
* The return value is a static buffer which is overwritten on each call.
*
* @param inaddr address (in network order)
* @return address in dot notation
*/
char *inet_ntoa(struct in_addr inaddr){
static char address[16] = {};
uint32_t addr = ntohl(inaddr.s_addr);
snprintf(address, sizeof(address), "%d.%d.%d.%d",
(unsigned)((addr >> 24) & 0xff),
(unsigned)((addr >> 16) & 0xff),
(unsigned)((addr >> 8) & 0xff),
(unsigned)((addr ) & 0xff));
return address;
}
/** Convert a string in IPv4 dot notation to an int in network order.
*
* @param address address in dot notation
* @param inp result of conversion (in network order)
* @return 0 on success, error code on error
*/
int inet_aton(const char *address, struct in_addr *inp){
int err = 0;
unsigned long addr;
err = get_inet_addr(address, &addr);
if(err) goto exit;
inp->s_addr = addr;
exit:
return err;
}
#endif
/** Convert a hostname or IPv4 address string to an address in network order.
*
* @param name input hostname or address string
* @param address where to put the address
* @return 1 if address found OK, 0 otherwise
*/
int get_host_address(const char *name, unsigned long *address){
#ifdef __KERNEL__
return get_inet_addr(name, address) == 0;
#else
struct hostent *host = gethostbyname(name);
if(!host){
return 0;
}
*address = ((struct in_addr *)(host->h_addr))->s_addr;
return 1;
#endif
}
/** Convert a service name to a port (in network order).
*
* @param name service name
* @param port where to put the port
* @return 1 if service port found OK, 0 otherwise
*/
int get_service_port(const char *name, unsigned long *port){
#ifdef __KERNEL__
return 0;
#else
struct servent *service;
service = getservbyname(name, 0);
if(!service){
return 0;
}
*port = service->s_port;
return 1;
#endif
}
/** Convert a port number (in network order) to a service name.
*
* @param port the port number
* @return service name if found OK, 0 otherwise
*/
char *get_port_service(unsigned long port){
#ifdef __KERNEL__
return 0;
#else
struct servent *service = getservbyport(port, 0);
return (service ? service->s_name : 0);
#endif
}
/** Convert a decimal integer or service name to a port (in network order).
*
* @param s input to convert
* @param port where to put the port
* @return 1 if port found OK, 0 otherwise
*/
int convert_service_to_port(const char *s, unsigned long *port){
int ok = 0;
unsigned long value;
if(convert_atoul(s, &value)){
ok = get_service_port(s, &value);
} else {
ok = (0 <= value) && (value <= PORT_MAX);
value = htons((unsigned short)value);
}
*port = (ok ? value : 0);
return ok;
}
#define MAC_ELEMENT_N 6 // Number of elements in a MAC address.
#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address.
#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)
/** Convert a mac address from a string of the form
* XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
* Each X denotes a hex digit: 0..9, a..f, A..F.
* Also supports using '-' as the separator instead of ':'.
*
* @param mac_in string to convert
* @param mac destination for the value
* @return 0 on success, -1 on error
*/
int mac_aton(const char *mac_in, unsigned char *mac){
int err = 0;
int i, j;
const char *p;
char sep = 0;
unsigned char d;
if(!mac_in || strlen(mac_in) != MAC_LENGTH){
err = -1;
goto exit;
}
for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
d = 0;
if(i){
if(!sep){
if(*p == ':' || *p == '-') sep = *p;
}
if(sep && *p == sep){
p++;
} else {
err = -1;
goto exit;
}
}
for(j = 0; j < MAC_DIGIT_N; j++, p++){
if(j) d <<= 4;
if(*p >= '0' && *p <= '9'){
d += (*p - '0');
} else if(*p >= 'A' && *p <= 'F'){
d += (*p - 'A') + 10;
} else if(*p >= 'a' && *p <= 'f'){
d += (*p - 'a') + 10;
} else {
err = -1;
goto exit;
}
}
mac[i] = d;
}
exit:
return err;
}
/** Convert a MAC address from numerical form to a string.
*
* @param mac address to convert
* @return static string value
*/
char *mac_ntoa(const unsigned char *mac){
static char buf[MAC_LENGTH + 1];
int buf_n = sizeof(buf);
memset(buf, buf_n, 0);
snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
buf[buf_n - 1] = '\0';
return buf;
}
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SYS_NET_H_
#define _XEN_LIB_SYS_NET_H_
/** @file
*
* Replacement for standard network includes.
* Works in user or kernel code.
*/
extern int get_inet_addr(const char *s, unsigned long *address);
extern unsigned long bits_to_mask(int n);
extern int mask_to_bits(unsigned long mask);
extern int get_host_address(const char *name, unsigned long *address);
extern int get_service_port(const char *name, unsigned long *port);
extern char *get_port_service(unsigned long port);
extern int convert_service_to_port(const char *s, unsigned long *port);
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
#ifndef htonl
#define htonl(x) __constant_htonl(x)
#endif
#ifndef ntohl
#define ntohl(x) __constant_ntohl(x)
#endif
#ifndef htons
#define htons(x) __constant_htons(x)
#endif
#ifndef ntohs
#define ntohs(x) __constant_ntohs(x)
#endif
#include <linux/in.h>
extern char *inet_ntoa(struct in_addr inaddr);
extern int inet_aton(const char *address, struct in_addr *inp);
#else
#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
extern char *mac_ntoa(const unsigned char *macaddr);
extern int mac_aton(const char *addr, unsigned char *macaddr);
#endif /* !_SP_SYS_NET_H_ */
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __KERNEL__
# include <linux/config.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
#else
# include <errno.h>
#endif
#include "allocate.h"
#include "sys_string.h"
/** Set the base to use for converting a string to a number. Base is
* hex if starts with 0x, otherwise decimal.
*
* @param s input string
* @param base where to put the base
* @return rest of s to parse as a number
*/
inline static const char * convert_set_base(const char *s, int *base){
*base = 10;
if(s){
if(*s=='0'){
s++;
if(*s=='x' || *s=='X'){
*base = 16;
s++;
}
}
}
return s;
}
/** Get the numerical value of a digit in the given base.
*
* @param c digit character
* @param base to use
* @return numerical value of digit in range 0..base-1 or
* -1 if not in range for the base
*/
inline static int convert_get_digit(char c, int base){
int d;
if('0'<=c && c<='9'){
d = c - '0';
} else if('a'<=c && c<='f'){
d = c - 'a' + 10;
} else if('A'<=c && c<='F'){
d = c - 'A' + 10;
} else {
d = -1;
}
return (d < base ? d : -1);
}
/** Convert a string to an unsigned long by parsing it as a number.
* Will accept hex or decimal in usual C syntax.
*
* @param str input string
* @param val where to put the result
* @return 0 if converted OK, negative otherwise
*/
int convert_atoul(const char *str, unsigned long *val){
int err = 0;
unsigned long v = 0;
int base;
const char *s = str;
if(!s) {
err = -EINVAL;
goto exit;
}
s = convert_set_base(s, &base);
for( ; !err && *s; s++){
int digit = convert_get_digit(*s, base);
if(digit<0){
err = -EINVAL;
goto exit;
}
v *= base;
v += digit;
}
exit:
*val = (err ? 0 : v);
return err;
}
/** Combine a directory path with a relative path to produce
* a new path.
*
* @param s directory path
* @param t relative path
* @return new combined path s/t
*/
int path_concat(char *s, char *t, char **val){
int err = 0;
int sn, tn, vn;
char *v;
sn = strlen(s);
if(sn > 0 && s[sn-1] == '/'){
sn--;
}
tn = strlen(t);
if(tn > 0 && t[0] == '/'){
tn--;
}
vn = sn+tn+1;
v = (char*)allocate(vn+1);
if(!v){
err = -ENOMEM;
goto exit;
}
strncpy(v, s, sn);
v[sn] = '/';
strncpy(v+sn+1, t, tn);
v[vn] = '\0';
exit:
*val = (err ? NULL : v);
return err;
}
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SYS_STRING_H_
#define _XEN_LIB_SYS_STRING_H_
/** @file
* Replacement for standard string includes.
* Works in user or kernel code.
*/
/*============================================================================*/
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <stdarg.h>
#include "allocate.h"
#if 0
static inline int tolower(int c){
return (c>='A' && c<='Z' ? (c-'A')+'a' : c);
}
#endif
static inline int isalpha(int c){
return (c>='A' && c<='Z') || (c>='a' && c<='z');
}
static inline int isdigit(int c){
return (c>='0' && c<='9');
}
#if 0
static inline int strcasecmp(const char *s1, const char *s2){
int c1, c2;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
} while (c1 && c1 == c2);
return c1 - c2;
}
#endif
static inline char * strdup(const char *s){
int n = (s ? 1+strlen(s) : 0);
char *copy = (n ? allocate(n) : NULL);
if(copy){
strcpy(copy, s);
}
return copy;
}
/*============================================================================*/
#else
#include <string.h>
#include <stdio.h>
#ifndef _GNU_SOURCE
static inline size_t strnlen(const char *s, size_t n){
int k = 0;
if(s){
for(k=0; *s && k<n; s++, k++){}
}
return k;
}
#endif
#endif
/*============================================================================*/
extern int convert_atoul(const char *s, unsigned long *v);
extern int path_concat(char *s, char *t, char **val);
#endif /* !_XEN_LIB_SYS_STRING_H_ */
+246
View File
@@ -0,0 +1,246 @@
/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */
#include "xdr.h"
#include <errno.h>
/** @file
* XDR packer/unpacker for elements.
*
* string -> [T_STRING] [len:u32] <len bytes>
* atom -> [T_ATOM] [len:u32] <len bytes>
* uint -> [T_UINT] [value]
* cons -> [T_CONS] <car> <cdr>
* null -> [T_NULL]
* none -> [T_NONE]
* bool -> [T_BOOL] { 0:u8 | 1:u8 }
*
* types packed as u16.
*
* So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
* () -> [T_NULL]
*/
int pack_bool(IOStream *io, int x){
int err=0;
err = IOStream_print(io, "%c", 0xff & x);
if(err > 0) err = 0;
return err;
}
int unpack_bool(IOStream *io, int *x){
int err = 0;
int c;
c = IOStream_getc(io);
*x = (c < 0 ? 0 : c);
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
return err;
}
int pack_ushort(IOStream *io, unsigned short x){
int err=0;
err = IOStream_print(io, "%c%c",
0xff & (x >> 8),
0xff & (x ));
if(err > 0) err = 0;
return err;
}
int unpack_ushort(IOStream *io, unsigned short *x){
int err = 0;
int i, c = 0;
*x = 0;
for(i = 0; i< 2; i++){
c = IOStream_getc(io);
if(c < 0) break;
*x <<= 8;
*x |= (0xff & c);
}
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
return err;
}
int pack_uint(IOStream *io, unsigned int x){
int err=0;
err = IOStream_print(io, "%c%c%c%c",
0xff & (x >> 24),
0xff & (x >> 16),
0xff & (x >> 8),
0xff & (x ));
if(err > 0) err = 0;
return err;
}
int unpack_uint(IOStream *io, unsigned int *x){
int err = 0;
int i, c = 0;
*x = 0;
for(i = 0; i< 4; i++){
c = IOStream_getc(io);
if(c < 0) break;
*x <<= 8;
*x |= (0xff & c);
}
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
return err;
}
int pack_string(IOStream *io, Sxpr x){
int err = 0;
int n = string_length(x);
char *s = string_string(x);
int i;
err = pack_uint(io, n);
if(err) goto exit;
for(i = 0; i < n; i++){
err = IOStream_print(io, "%c", s[i]);
if(err < 0) break;
}
if(err > 0) err = 0;
exit:
return err;
}
int unpack_string(IOStream *io, Sxpr *x){
int err;
unsigned int n;
int i, c = 0;
char *s;
Sxpr val = ONONE;
err = unpack_uint(io, &n);
if(err) goto exit;
val = halloc(n+1, T_STRING);
if(NOMEMP(val)){
err = -ENOMEM;
goto exit;
}
s = string_string(val);
for(i=0; i<n; i++){
c = IOStream_getc(io);
if(c < 0) break;
s[i] = (char)c;
}
s[n] = '\0';
exit:
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
if(err){
objfree(val);
val = ONONE;
}
*x = val;
return err;
}
int pack_cons(IOStream *io, Sxpr x){
int err = 0;
err = pack_sxpr(io, CAR(x));
if(err) goto exit;
err = pack_sxpr(io, CDR(x));
exit:
return err;
}
int unpack_cons(IOStream *io, Sxpr *x){
int err = 0;
Sxpr u = ONONE, v = ONONE, val = ONONE;
err = unpack_sxpr(io, &u);
if(err) goto exit;
err = unpack_sxpr(io, &v);
if(err) goto exit;
val = cons_new(u, v);
if(NOMEMP(val)){
err = -ENOMEM;
}
exit:
if(err){
objfree(u);
objfree(v);
val = ONONE;
}
*x = val;
return err;
}
int pack_sxpr(IOStream *io, Sxpr x){
int err = 0;
unsigned short type = get_type(x);
err = pack_ushort(io, type);
if(err) goto exit;
switch(type){
case T_NULL:
break;
case T_NONE:
break;
break;
case T_BOOL:
err = pack_bool(io, get_ul(x));
break;
case T_CONS:
err = pack_cons(io, x);
break;
case T_ATOM:
err = pack_string(io, OBJ_ATOM(x)->name);
break;
case T_STRING:
err = pack_string(io, x);
break;
case T_UINT:
err = pack_uint(io, get_ul(x));
break;
default:
err = -EINVAL;
IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
break;
}
exit:
return err;
}
int unpack_sxpr(IOStream *io, Sxpr *x){
int err = 0;
unsigned short type;
unsigned int u;
Sxpr val = ONONE, y;
err = unpack_ushort(io, &type);
if(err) goto exit;
switch(type){
case T_NULL:
val = ONULL;
break;
case T_NONE:
val = ONONE;
break;
case T_CONS:
err = unpack_cons(io, &val);
break;
case T_BOOL:
err = unpack_bool(io, &u);
if(err) goto exit;
val = (u ? OTRUE : OFALSE);
break;
case T_ATOM:
err = unpack_string(io, &y);
if(err) goto exit;
val = intern(string_string(y));
objfree(y);
break;
case T_STRING:
err = unpack_string(io, &val);
break;
case T_UINT:
err = unpack_uint(io, &u);
if(err) goto exit;
val = OBJI(type, u);
break;
default:
err = -EINVAL;
IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
break;
}
exit:
*x = (err ? ONONE : val);
return err;
}
+14
View File
@@ -0,0 +1,14 @@
/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */
#ifndef _SP_XDR_H_
#define _SP_XDR_H_
#include "iostream.h"
#include "sxpr.h"
int pack_uint(IOStream *out, unsigned int x);
int unpack_uint(IOStream *in, unsigned int *x);
int pack_string(IOStream *out, Sxpr x);
int unpack_string(IOStream *in, Sxpr *x);
int pack_cons(IOStream *out, Sxpr x);
int unpack_cons(IOStream *in, Sxpr *x);
int pack_sxpr(IOStream *out, Sxpr x);
int unpack_sxpr(IOStream *in, Sxpr *x);
#endif /* _SP_XDR_H_ */
+1
View File
@@ -4,6 +4,7 @@ CFLAGS = -Wall -O3
EXTRA_INC = -I../../xen/include/hypervisor-ifs
EXTRA_INC += -I../../linux-xen-sparse/include -I../xc/lib
EXTRA_INC += -I../xu/lib
EXTRA_INC += -I../lib
HDRS = $(wildcard *.h)
SRCS = $(wildcard *.c)
+73 -8
View File
@@ -4,13 +4,73 @@ MINOR = 0
SONAME = libxc.so.$(MAJOR)
CC = gcc
CFLAGS = -c -Werror -O3 -fno-strict-aliasing
CFLAGS += -I../../../xen/include/hypervisor-ifs
CFLAGS += -I../../xu/lib
CFLAGS += -I../../../linux-xen-sparse/include
HDRS = $(wildcard *.h)
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
XEN_ROOT = ../../..
vpath %.h $(XEN_ROOT)/xen/include/hypervisor-ifs
INCLUDES += -I $(XEN_ROOT)/xen/include/hypervisor-ifs
vpath %.h $(XEN_ROOT)/tools/xu/lib
INCLUDES += -I $(XEN_ROOT)/tools/xu/lib
vpath %h $(XEN_ROOT)/linux-xen-sparse/include
INCLUDES += -I $(XEN_ROOT)/linux-xen-sparse/include
vpath %c $(XEN_ROOT)/tools/lib
INCLUDES += -I $(XEN_ROOT)/tools/lib
LIB_SRCS :=
LIB_SRCS += allocate.c
#LIB_SRCS += enum.c
LIB_SRCS += file_stream.c
LIB_SRCS += gzip_stream.c
#LIB_SRCS += hash_table.c
LIB_SRCS += iostream.c
#LIB_SRCS += kernel_stream.c
#LIB_SRCS += lexis.c
#LIB_SRCS += lzi_stream.c
#LIB_SRCS += lzo_stream.c
#LIB_SRCS += marshal.c
#LIB_SRCS += socket_stream.c
#LIB_SRCS += string_stream.c
#LIB_SRCS += sxpr.c
#LIB_SRCS += sxpr_parser.c
LIB_SRCS += sys_net.c
LIB_SRCS += sys_string.c
#LIB_SRCS += xdr.c
SRCS :=
SRCS += xc_atropos.c
SRCS += xc_bvtsched.c
SRCS += xc_domain.c
SRCS += xc_evtchn.c
SRCS += xc_io.c
SRCS += xc_linux_build.c
SRCS += xc_linux_restore.c
SRCS += xc_linux_save.c
SRCS += xc_misc.c
SRCS += xc_netbsd_build.c
SRCS += xc_physdev.c
SRCS += xc_private.c
SRCS += xc_rrobin.c
SRCS += $(LIB_SRCS)
#CFLAGS += -I../../../xen/include/hypervisor-ifs
#CFLAGS += -I../../xu/lib
#CFLAGS += -I../../../linux-xen-sparse/include
CFLAGS += -Wall
CFLAGS += -Werror
CFLAGS += -g
CFLAGS += -O3
CFLAGS += -fno-strict-aliasing
CFLAGS += $(INCLUDES)
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
OBJS = $(patsubst %.c,%.o,$(SRCS))
LIB = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
@@ -32,6 +92,8 @@ install: all
clean:
$(RM) *.a *.so *.o *.rpm $(LIB)
$(RM) *~
$(RM) $(DEPS)
rpm: all
rm -rf staging
@@ -49,5 +111,8 @@ libxc.so.$(MAJOR):
libxc.so.$(MAJOR).$(MINOR): $(OBJS)
$(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ -lz
%.o: %.c $(HDRS) Makefile
$(CC) $(CFLAGS) -o $@ $<
%.o: %.c Makefile
# $(CC) $(CFLAGS) -o $@ $<
-include $(DEPS)
+3 -12
View File
@@ -75,18 +75,9 @@ int xc_shadow_control(int xc_handle,
#define XCFLAGS_LIVE 2
#define XCFLAGS_DEBUG 4
int xc_linux_save(int xc_handle,
u32 domid,
unsigned int flags,
int (*writerfn)(void *, const void *, size_t),
void *writerst);
int xc_linux_restore(int xc_handle,
u32 domid,
unsigned int flags,
int (*readerfn)(void *, void *, size_t),
void *readerst,
u32 *pdomid);
struct XcIOContext;
int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt);
int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt);
int xc_linux_build(int xc_handle,
u32 domid,
+27
View File
@@ -0,0 +1,27 @@
#include "xc_io.h"
void xcio_error(XcIOContext *ctxt, const char *msg, ...){
va_list args;
va_start(args, msg);
IOStream_vprint(ctxt->info, msg, args);
va_end(args);
}
void xcio_info(XcIOContext *ctxt, const char *msg, ...){
va_list args;
if(!(ctxt->flags & XCFLAGS_VERBOSE)) return;
va_start(args, msg);
IOStream_vprint(ctxt->info, msg, args);
va_end(args);
}
void xcio_debug(XcIOContext *ctxt, const char *msg, ...){
va_list args;
if(!(ctxt->flags & XCFLAGS_DEBUG)) return;
va_start(args, msg);
IOStream_vprint(ctxt->info, msg, args);
va_end(args);
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef __XC_XC_IO_H__
#define __XC_XC_IO_H__
#include "xc_private.h"
#include "iostream.h"
typedef struct XcIOContext {
u32 domain;
unsigned flags;
IOStream *io;
IOStream *info;
IOStream *err;
char *vmconfig;
int vmconfig_n;
} XcIOContext;
static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){
int rc;
rc = IOStream_read(ctxt->io, buf, n);
return (rc == n ? 0 : rc);
}
static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){
int rc;
rc = IOStream_write(ctxt->io, buf, n);
return (rc == n ? 0 : rc);
}
static inline int xcio_flush(XcIOContext *ctxt){
return IOStream_flush(ctxt->io);
}
extern void xcio_error(XcIOContext *ctxt, const char *msg, ...);
extern void xcio_info(XcIOContext *ctxt, const char *msg, ...);
#define xcio_perror(_ctxt, _msg...) \
xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg)
#endif /* ! __XC_XC_IO_H__ */
+158 -188
View File
@@ -8,7 +8,6 @@
#include "xc_private.h"
#include <asm-xen/suspend.h>
#include <zlib.h>
#define MAX_BATCH_SIZE 1024
@@ -21,14 +20,6 @@
#endif
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
if ( !verbose ) break; \
printf( _f , ## _a ); \
fflush(stdout); \
} while ( 0 )
static int get_pfn_list(int xc_handle,
u32 domain_id,
unsigned long *pfn_buf,
@@ -54,19 +45,44 @@ static int get_pfn_list(int xc_handle,
return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
}
/** Read the vmconfig string from the state input.
* It is stored as a 4-byte count 'n' followed by n bytes.
* The config data is stored in a new string in 'ioctxt->vmconfig',
* and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'.
*
* @param ioctxt i/o context
* @return 0 on success, non-zero on error.
*/
static int read_vmconfig(XcIOContext *ioctxt){
int err = -1;
if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){
goto exit;
}
ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1);
if(!ioctxt->vmconfig) goto exit;
if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){
goto exit;
}
ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0';
err = 0;
exit:
if(err){
if(ioctxt->vmconfig){
free(ioctxt->vmconfig);
}
ioctxt->vmconfig = NULL;
ioctxt->vmconfig_n = 0;
}
return err;
}
int xc_linux_restore(int xc_handle,
u32 dom,
unsigned int flags,
int (*readerfn)(void *, void *, size_t),
void *readerst,
u32 *pdomid)
int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
{
dom0_op_t op;
int rc = 1, i, j, n, k;
int rc = 1, i, n, k;
unsigned long mfn, pfn, xpfn;
unsigned int prev_pc, this_pc;
int verbose = flags & XCFLAGS_VERBOSE;
u32 dom = ioctxt->domain;
int verify = 0;
/* Number of page frames in use by this Linux session. */
@@ -115,8 +131,7 @@ int xc_linux_restore(int xc_handle,
/* used by debug verify code */
unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
if ( mlock(&ctxt, sizeof(ctxt) ) ) {
/* needed for when we do the build dom0 op,
but might as well do early */
PERROR("Unable to mlock ctxt");
@@ -124,35 +139,36 @@ int xc_linux_restore(int xc_handle,
}
/* Start writing out the saved-domain record. */
if ( (*readerfn)(readerst, signature, 16) ||
(memcmp(signature, "LinuxGuestRecord", 16) != 0) )
{
ERROR("Unrecognised state format -- no signature found");
if ( xcio_read(ioctxt, signature, 16) ||
(memcmp(signature, "LinuxGuestRecord", 16) != 0) ) {
xcio_error(ioctxt, "Unrecognised state format -- no signature found");
goto out;
}
if ( (*readerfn)(readerst, name, sizeof(name)) ||
(*readerfn)(readerst, &nr_pfns, sizeof(unsigned long)) ||
(*readerfn)(readerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
{
ERROR("Error when reading from state file");
if ( xcio_read(ioctxt, name, sizeof(name)) ||
xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) {
xcio_error(ioctxt, "Error reading header");
goto out;
}
for ( i = 0; i < MAX_DOMAIN_NAME; i++ )
{
if(read_vmconfig(ioctxt)){
xcio_error(ioctxt, "Error writing vmconfig");
goto out;
}
for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) {
if ( name[i] == '\0' ) break;
if ( name[i] & 0x80 )
{
ERROR("Random characters in domain name");
xcio_error(ioctxt, "Random characters in domain name");
goto out;
}
}
name[MAX_DOMAIN_NAME-1] = '\0';
if ( nr_pfns > 1024*1024 )
{
ERROR("Invalid state file -- pfn count out of range");
if ( nr_pfns > 1024*1024 ) {
xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
goto out;
}
@@ -162,22 +178,19 @@ int xc_linux_restore(int xc_handle,
region_mfn = calloc(1, 4 * MAX_BATCH_SIZE);
if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) ||
(region_mfn == NULL) )
{
(region_mfn == NULL) ) {
errno = ENOMEM;
goto out;
}
if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) )
{
ERROR("Could not mlock region_mfn");
if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) {
xcio_error(ioctxt, "Could not mlock region_mfn");
goto out;
}
/* Set the domain's name to that from the restore file */
if ( xc_domain_setname( xc_handle, dom, name ) )
{
ERROR("Could not set domain name");
if ( xc_domain_setname( xc_handle, dom, name ) ) {
xcio_error(ioctxt, "Could not set domain name");
goto out;
}
@@ -187,7 +200,7 @@ int xc_linux_restore(int xc_handle,
if ( xc_domain_setinitialmem(xc_handle, dom,
nr_pfns * (PAGE_SIZE / 1024)) )
{
ERROR("Could not set domain initial memory");
xcio_error(ioctxt, "Could not set domain initial memory");
goto out;
}
@@ -195,9 +208,8 @@ int xc_linux_restore(int xc_handle,
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)dom;
op.u.getdomaininfo.ctxt = NULL;
if ( do_dom0_op(xc_handle, &op) < 0 )
{
ERROR("Could not get information on new domain");
if ( do_dom0_op(xc_handle, &op) < 0 ) {
xcio_error(ioctxt, "Could not get information on new domain");
goto out;
}
shared_info_frame = op.u.getdomaininfo.shared_info_frame;
@@ -208,19 +220,17 @@ int xc_linux_restore(int xc_handle,
/* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
{
ERROR("Did not read correct number of frame numbers for new dom");
if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) {
xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom");
goto out;
}
if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
{
ERROR("Could not initialise for MMU updates");
if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) {
xcio_error(ioctxt, "Could not initialise for MMU updates");
goto out;
}
verbose_printf("Reloading memory pages: 0%%");
xcio_info(ioctxt, "Reloading memory pages: 0%%");
/*
* Now simply read each saved frame into its new machine frame.
@@ -229,56 +239,45 @@ int xc_linux_restore(int xc_handle,
prev_pc = 0;
n=0;
while(1)
{
while(1) {
int j;
unsigned long region_pfn_type[MAX_BATCH_SIZE];
this_pc = (n * 100) / nr_pfns;
if ( (this_pc - prev_pc) >= 5 )
{
verbose_printf("\b\b\b\b%3d%%", this_pc);
if ( (this_pc - prev_pc) >= 5 ) {
xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
prev_pc = this_pc;
}
if ( (*readerfn)(readerst, &j, sizeof(int)) )
{
ERROR("Error when reading from state file");
if ( xcio_read(ioctxt, &j, sizeof(int)) ) {
xcio_error(ioctxt, "Error when reading from state file");
goto out;
}
DPRINTF("batch %d\n",j);
if ( j == -1 )
{
if ( j == -1 ) {
verify = 1;
printf("Entering page verify mode\n");
continue;
}
if ( j == 0 )
break; /* our work here is done */
if ( j == 0 ) break; /* our work here is done */
if( j > MAX_BATCH_SIZE )
{
ERROR("Max batch size exceeded. Giving up.");
if( j > MAX_BATCH_SIZE ) {
xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
goto out;
}
if ( (*readerfn)(readerst, region_pfn_type, j*sizeof(unsigned long)) )
{
ERROR("Error when reading from state file");
if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
xcio_error(ioctxt, "Error when reading from state file");
goto out;
}
for(i=0;i<j;i++)
{
if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
{
for(i=0; i<j; i++) {
if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) {
region_mfn[i] = 0; /* we know map will fail, but don't care */
}
else
{
} else {
pfn = region_pfn_type[i] & ~LTAB_MASK;
region_mfn[i] = pfn_to_mfn_table[pfn];
}
@@ -287,24 +286,20 @@ int xc_linux_restore(int xc_handle,
if ( (region_base = mfn_mapper_map_batch( xc_handle, dom,
PROT_WRITE,
region_mfn,
j )) == 0)
{
PERROR("map batch failed");
j )) == 0) {
xcio_error(ioctxt, "map batch failed");
goto out;
}
for(i=0;i<j;i++)
{
for(i=0;i<j;i++) {
unsigned long *ppage;
pfn = region_pfn_type[i] & ~LTAB_MASK;
if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
continue;
if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
if (pfn>nr_pfns)
{
ERROR("pfn out of range");
if (pfn>nr_pfns) {
xcio_error(ioctxt, "pfn out of range");
goto out;
}
@@ -314,36 +309,32 @@ int xc_linux_restore(int xc_handle,
mfn = pfn_to_mfn_table[pfn];
if ( verify )
if ( verify ) {
ppage = (unsigned long*) buf; /* debug case */
else
} else {
ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
}
if ( (*readerfn)(readerst, ppage, PAGE_SIZE) )
{
ERROR("Error when reading from state file");
if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) {
xcio_error(ioctxt, "Error when reading from state file");
goto out;
}
switch( region_pfn_type[i] )
{
switch( region_pfn_type[i] ) {
case 0:
break;
case L1TAB:
{
for ( k = 0; k < 1024; k++ )
{
if ( ppage[k] & _PAGE_PRESENT )
{
for ( k = 0; k < 1024; k++ ) {
if ( ppage[k] & _PAGE_PRESENT ) {
xpfn = ppage[k] >> PAGE_SHIFT;
if ( xpfn >= nr_pfns )
{
ERROR("Frame number in type %d page table is "
"out of range. i=%d k=%d pfn=0x%x "
"nr_pfns=%d", region_pfn_type[i]>>28, i,
k, xpfn,nr_pfns);
if ( xpfn >= nr_pfns ) {
xcio_error(ioctxt, "Frame number in type %lu page table is "
"out of range. i=%d k=%d pfn=0x%lx "
"nr_pfns=%lu", region_pfn_type[i]>>28, i,
k, xpfn, nr_pfns);
goto out;
}
@@ -359,16 +350,13 @@ int xc_linux_restore(int xc_handle,
{
for ( k = 0;
k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT);
k++ )
{
if ( ppage[k] & _PAGE_PRESENT )
{
k++ ) {
if ( ppage[k] & _PAGE_PRESENT ) {
xpfn = ppage[k] >> PAGE_SHIFT;
if ( xpfn >= nr_pfns )
{
ERROR("Frame number in type %d page table is "
"out of range. i=%d k=%d pfn=%d nr_pfns=%d",
if ( xpfn >= nr_pfns ) {
xcio_error(ioctxt, "Frame number in type %lu page table is "
"out of range. i=%d k=%d pfn=%lu nr_pfns=%lu",
region_pfn_type[i]>>28, i, k, xpfn, nr_pfns);
goto out;
@@ -383,24 +371,21 @@ int xc_linux_restore(int xc_handle,
break;
default:
ERROR("Bogus page type %x page table is out of range."
" i=%d nr_pfns=%d", region_pfn_type[i], i, nr_pfns);
xcio_error(ioctxt, "Bogus page type %lx page table is out of range."
" i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns);
goto out;
} /* end of page type switch statement */
if ( verify )
{
if ( verify ) {
int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
if (res)
{
if (res) {
int v;
printf("************** pfn=%x type=%x gotcs=%08lx "
printf("************** pfn=%lx type=%lx gotcs=%08lx "
"actualcs=%08lx\n", pfn, pfn_type[pfn],
csum_page(region_base + i*PAGE_SIZE),
csum_page(buf));
for ( v = 0; v < 4; v++ )
{
for ( v = 0; v < 4; v++ ) {
unsigned long *p = (unsigned long *)
(region_base + i*PAGE_SIZE);
if ( buf[v] != p[v] )
@@ -411,8 +396,7 @@ int xc_linux_restore(int xc_handle,
}
if ( add_mmu_update(xc_handle, mmu,
(mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
{
(mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) ) {
printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
goto out;
}
@@ -431,44 +415,36 @@ int xc_linux_restore(int xc_handle,
* Pin page tables. Do this after writing to them as otherwise Xen
* will barf when doing the type-checking.
*/
for ( i = 0; i < nr_pfns; i++ )
{
if ( pfn_type[i] == L1TAB )
{
for ( i = 0; i < nr_pfns; i++ ) {
if ( pfn_type[i] == L1TAB ) {
if ( add_mmu_update(xc_handle, mmu,
(pfn_to_mfn_table[i]<<PAGE_SHIFT) |
MMU_EXTENDED_COMMAND,
MMUEXT_PIN_L1_TABLE) )
{
MMUEXT_PIN_L1_TABLE) ) {
printf("ERR pin L1 pfn=%lx mfn=%lx\n",
i, pfn_to_mfn_table[i]);
(unsigned long)i, pfn_to_mfn_table[i]);
goto out;
}
}
else if ( pfn_type[i] == L2TAB )
{
} else if ( pfn_type[i] == L2TAB ) {
if ( add_mmu_update(xc_handle, mmu,
(pfn_to_mfn_table[i]<<PAGE_SHIFT) |
MMU_EXTENDED_COMMAND,
MMUEXT_PIN_L2_TABLE) )
{
MMUEXT_PIN_L2_TABLE) ) {
printf("ERR pin L2 pfn=%lx mfn=%lx\n",
i, pfn_to_mfn_table[i]);
(unsigned long)i, pfn_to_mfn_table[i]);
goto out;
}
}
}
if ( finish_mmu_updates(xc_handle, mmu) )
goto out;
if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
verbose_printf("\b\b\b\b100%%\nMemory reloaded.\n");
xcio_info(ioctxt, "\b\b\b\b100%%\nMemory reloaded.\n");
if ( (*readerfn)(readerst, &ctxt, sizeof(ctxt)) ||
(*readerfn)(readerst, shared_info, PAGE_SIZE) )
{
ERROR("Error when reading from state file");
if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
xcio_read(ioctxt, shared_info, PAGE_SIZE) ) {
xcio_error(ioctxt, "Error when reading from state file");
goto out;
}
@@ -476,7 +452,7 @@ int xc_linux_restore(int xc_handle,
pfn = ctxt.cpu_ctxt.esi;
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
{
ERROR("Suspend record frame number is bad");
xcio_error(ioctxt, "Suspend record frame number is bad");
goto out;
}
ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
@@ -487,17 +463,14 @@ int xc_linux_restore(int xc_handle,
unmap_pfn(pm_handle, p_srec);
/* Uncanonicalise each GDT frame number. */
if ( ctxt.gdt_ents > 8192 )
{
ERROR("GDT entry count out of range");
if ( ctxt.gdt_ents > 8192 ) {
xcio_error(ioctxt, "GDT entry count out of range");
goto out;
}
for ( i = 0; i < ctxt.gdt_ents; i += 512 )
{
for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
pfn = ctxt.gdt_frames[i];
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
{
ERROR("GDT frame number is bad");
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
xcio_error(ioctxt, "GDT frame number is bad");
goto out;
}
ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
@@ -505,11 +478,10 @@ int xc_linux_restore(int xc_handle,
/* Uncanonicalise the page table base pointer. */
pfn = ctxt.pt_base >> PAGE_SHIFT;
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) )
{
printf("PT base is bad. pfn=%d nr=%d type=%08lx %08lx\n",
pfn, nr_pfns, pfn_type[pfn], L2TAB);
ERROR("PT base is bad.");
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) {
printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
xcio_error(ioctxt, "PT base is bad.");
goto out;
}
ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
@@ -527,14 +499,12 @@ int xc_linux_restore(int xc_handle,
/* Uncanonicalise the pfn-to-mfn table frame-number list. */
for ( i = 0; i < (nr_pfns+1023)/1024; i++ )
{
for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) {
unsigned long pfn, mfn;
pfn = pfn_to_mfn_frame_list[i];
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
{
ERROR("PFN-to-MFN frame number is bad");
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
goto out;
}
mfn = pfn_to_mfn_table[pfn];
@@ -545,9 +515,8 @@ int xc_linux_restore(int xc_handle,
mfn_mapper_map_batch(xc_handle, dom,
PROT_WRITE,
pfn_to_mfn_frame_list,
(nr_pfns+1023)/1024 )) == 0 )
{
ERROR("Couldn't map pfn_to_mfn table");
(nr_pfns+1023)/1024 )) == 0 ) {
xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
goto out;
}
@@ -569,24 +538,26 @@ int xc_linux_restore(int xc_handle,
* 9. debugregs are checked by Xen.
* 10. callback code selectors need checking.
*/
for ( i = 0; i < 256; i++ )
{
for ( i = 0; i < 256; i++ ) {
ctxt.trap_ctxt[i].vector = i;
if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
}
if ( (ctxt.guestos_ss & 3) == 0 )
if ( (ctxt.guestos_ss & 3) == 0 ){
ctxt.guestos_ss = FLAT_GUESTOS_DS;
if ( (ctxt.event_callback_cs & 3) == 0 )
}
if ( (ctxt.event_callback_cs & 3) == 0 ){
ctxt.event_callback_cs = FLAT_GUESTOS_CS;
if ( (ctxt.failsafe_callback_cs & 3) == 0 )
}
if ( (ctxt.failsafe_callback_cs & 3) == 0 ){
ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
}
if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
(ctxt.ldt_ents > 8192) ||
(ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
{
ERROR("Bad LDT base or size");
xcio_error(ioctxt, "Bad LDT base or size");
goto out;
}
@@ -597,34 +568,33 @@ int xc_linux_restore(int xc_handle,
/* don't start the domain as we have console etc to set up */
if( rc == 0 )
{
if( rc == 0 ) {
/* Success: print the domain id. */
verbose_printf("DOM=%u\n", dom);
xcio_info(ioctxt, "DOM=%lu\n", dom);
return 0;
}
out:
if ( (rc != 0) && (dom != 0) )
if ( (rc != 0) && (dom != 0) ){
xc_domain_destroy(xc_handle, dom);
if ( mmu != NULL )
}
if ( mmu != NULL ){
free(mmu);
if ( pm_handle >= 0 )
}
if ( pm_handle >= 0 ){
(void)close_pfn_mapper(pm_handle);
if ( pfn_to_mfn_table != NULL )
}
if ( pfn_to_mfn_table != NULL ){
free(pfn_to_mfn_table);
if ( pfn_type != NULL )
}
if ( pfn_type != NULL ){
free(pfn_type);
}
if ( rc == 0 )
*pdomid = dom;
if ( rc == 0 ){
ioctxt->domain = dom;
}
DPRINTF("Restore exit with rc=%d\n",rc);
return rc;
}
+129 -172
View File
@@ -6,6 +6,7 @@
* Copyright (c) 2003, K A Fraser.
*/
#include <sys/time.h>
#include "xc_private.h"
#include <asm-xen/suspend.h>
@@ -26,14 +27,6 @@
#define DDPRINTF(_f, _a...) ((void)0)
#endif
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
if ( !verbose ) break; \
printf( _f , ## _a ); \
fflush(stdout); \
} while ( 0 )
/*
* Returns TRUE if the given machine frame number has a unique mapping
* in the guest's pseudophysical map.
@@ -189,6 +182,20 @@ static int print_stats( int xc_handle, u32 domid,
return 0;
}
/** Write the vmconfig string.
* It is stored as a 4-byte count 'n' followed by n bytes.
*
* @param ioctxt i/o context
* @return 0 on success, non-zero on error.
*/
static int write_vmconfig(XcIOContext *ioctxt){
int err = -1;
if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit;
if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit;
err = 0;
exit:
return err;
}
static int analysis_phase( int xc_handle, u32 domid,
int nr_pfns, unsigned long *arr )
@@ -225,19 +232,15 @@ static int analysis_phase( int xc_handle, u32 domid,
return -1;
}
int xc_linux_save(int xc_handle,
u32 domid,
unsigned int flags,
int (*writerfn)(void *, const void *, size_t),
void *writerst )
int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
{
dom0_op_t op;
int rc = 1, i, j, k, last_iter, iter = 0;
unsigned long mfn;
int verbose = flags & XCFLAGS_VERBOSE;
int live = flags & XCFLAGS_LIVE;
int debug = flags & XCFLAGS_DEBUG;
int sent_last_iter, sent_this_iter, skip_this_iter;
u32 domid = ioctxt->domain;
int live = (ioctxt->flags & XCFLAGS_LIVE);
int debug = (ioctxt->flags & XCFLAGS_DEBUG);
int sent_last_iter, skip_this_iter;
/* Important tuning parameters */
int max_iters = 29; /* limit us to 30 times round loop */
@@ -272,7 +275,7 @@ int xc_linux_save(int xc_handle,
unsigned long *live_shinfo;
/* base of the region in which domain memory is mapped */
unsigned char *region_base;
unsigned char *region_base = NULL;
/* A temporary mapping, and a copy, of the guest's suspend record. */
suspend_record_t *p_srec;
@@ -294,17 +297,14 @@ int xc_linux_save(int xc_handle,
int needed_to_fix = 0;
int total_sent = 0;
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
PERROR("Unable to mlock ctxt");
if (mlock(&ctxt, sizeof(ctxt))) {
xcio_perror(ioctxt, "Unable to mlock ctxt");
return 1;
}
/* Ensure that the domain exists, and that it is stopped. */
if ( xc_domain_pause( xc_handle, domid ) )
{
PERROR("Could not pause domain");
if ( xc_domain_pause(xc_handle, domid) ){
xcio_perror(ioctxt, "Could not pause domain");
goto out;
}
@@ -317,9 +317,8 @@ int xc_linux_save(int xc_handle,
shared_info_frame = op.u.getdomaininfo.shared_info_frame;
/* A cheesy test to see whether the domain contains valid state. */
if ( ctxt.pt_base == 0 )
{
ERROR("Domain is not in a valid Linux guest OS state");
if ( ctxt.pt_base == 0 ){
xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state");
goto out;
}
@@ -327,20 +326,17 @@ int xc_linux_save(int xc_handle,
domid for this to succeed. */
p_srec = mfn_mapper_map_single(xc_handle, domid,
sizeof(*p_srec), PROT_READ,
ctxt.cpu_ctxt.esi );
if (!p_srec)
{
ERROR("Couldn't map state record");
ctxt.cpu_ctxt.esi);
if (!p_srec){
xcio_error(ioctxt, "Couldn't map state record");
goto out;
}
nr_pfns = p_srec->nr_pfns;
/* cheesy sanity check */
if ( nr_pfns > 1024*1024 )
{
ERROR("Invalid state record -- pfn count out of range");
if ( nr_pfns > 1024*1024 ){
xcio_error(ioctxt, "Invalid state record -- pfn count out of range");
goto out;
}
@@ -350,9 +346,8 @@ int xc_linux_save(int xc_handle,
PAGE_SIZE, PROT_READ,
p_srec->pfn_to_mfn_frame_list );
if (!live_pfn_to_mfn_frame_list)
{
ERROR("Couldn't map pfn_to_mfn_frame_list");
if (!live_pfn_to_mfn_frame_list){
xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list");
goto out;
}
@@ -379,24 +374,21 @@ int xc_linux_save(int xc_handle,
(its not clear why it would want to change them, and we'll be OK
from a safety POV anyhow. */
live_pfn_to_mfn_table = mfn_mapper_map_batch( xc_handle, domid,
PROT_READ,
live_pfn_to_mfn_frame_list,
(nr_pfns+1023)/1024 );
if( !live_pfn_to_mfn_table )
{
PERROR("Couldn't map pfn_to_mfn table");
live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid,
PROT_READ,
live_pfn_to_mfn_frame_list,
(nr_pfns+1023)/1024 );
if( !live_pfn_to_mfn_table ){
xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table");
goto out;
}
/* Canonicalise the pfn-to-mfn table frame-number list. */
memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
for ( i = 0; i < nr_pfns; i += 1024 )
{
if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) )
{
ERROR("Frame # in pfn-to-mfn frame list is not in pseudophys");
for ( i = 0; i < nr_pfns; i += 1024 ){
if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){
xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys");
goto out;
}
}
@@ -404,27 +396,24 @@ int xc_linux_save(int xc_handle,
/* At this point, we can start the domain again if we're doing a
live suspend */
if( live )
{
if( live ){
if ( xc_shadow_control( xc_handle, domid,
DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
NULL, 0, NULL ) < 0 )
{
ERROR("Couldn't enable shadow mode");
NULL, 0, NULL ) < 0 ) {
xcio_error(ioctxt, "Couldn't enable shadow mode");
goto out;
}
if ( xc_domain_unpause( xc_handle, domid ) < 0 )
{
ERROR("Couldn't unpause domain");
if ( xc_domain_unpause(xc_handle, domid) < 0 ){
xcio_error(ioctxt, "Couldn't unpause domain");
goto out;
}
last_iter = 0;
sent_last_iter = 1<<20; /* 4GB of pages */
}
else
} else{
last_iter = 1;
}
/* calculate the power of 2 order of nr_pfns, e.g.
15->4 16->4 17->5 */
@@ -438,25 +427,22 @@ int xc_linux_save(int xc_handle,
to_fix = calloc( 1, sz );
to_skip = malloc( sz );
if (!to_send || !to_fix || !to_skip)
{
ERROR("Couldn't allocate to_send array");
if (!to_send || !to_fix || !to_skip){
xcio_error(ioctxt, "Couldn't allocate to_send array");
goto out;
}
memset( to_send, 0xff, sz );
if ( mlock( to_send, sz ) )
{
PERROR("Unable to mlock to_send");
if ( mlock( to_send, sz ) ){
xcio_perror(ioctxt, "Unable to mlock to_send");
return 1;
}
/* (to fix is local only) */
if ( mlock( to_skip, sz ) )
{
PERROR("Unable to mlock to_skip");
if ( mlock( to_skip, sz ) ){
xcio_perror(ioctxt, "Unable to mlock to_skip");
return 1;
}
@@ -468,15 +454,13 @@ int xc_linux_save(int xc_handle,
pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long));
if ( (pfn_type == NULL) || (pfn_batch == NULL) )
{
if ( (pfn_type == NULL) || (pfn_batch == NULL) ){
errno = ENOMEM;
goto out;
}
if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) )
{
ERROR("Unable to mlock");
if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){
xcio_error(ioctxt, "Unable to mlock");
goto out;
}
@@ -485,8 +469,7 @@ int xc_linux_save(int xc_handle,
* Quick belt and braces sanity check.
*/
#if DEBUG
for ( i = 0; i < nr_pfns; i++ )
{
for ( i = 0; i < nr_pfns; i++ ){
mfn = live_pfn_to_mfn_table[i];
if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
@@ -500,20 +483,22 @@ int xc_linux_save(int xc_handle,
PAGE_SIZE, PROT_READ,
shared_info_frame);
if (!live_shinfo)
{
ERROR("Couldn't map live_shinfo");
if (!live_shinfo){
xcio_error(ioctxt, "Couldn't map live_shinfo");
goto out;
}
/* Start writing out the saved-domain record. */
if ( (*writerfn)(writerst, "LinuxGuestRecord", 16) ||
(*writerfn)(writerst, name, sizeof(name)) ||
(*writerfn)(writerst, &nr_pfns, sizeof(unsigned long)) ||
(*writerfn)(writerst, pfn_to_mfn_frame_list, PAGE_SIZE) )
{
ERROR("Error when writing to state file (1)");
if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) ||
xcio_write(ioctxt, name, sizeof(name)) ||
xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){
xcio_error(ioctxt, "Error writing header");
goto out;
}
if(write_vmconfig(ioctxt)){
xcio_error(ioctxt, "Error writing vmconfig");
goto out;
}
@@ -521,8 +506,7 @@ int xc_linux_save(int xc_handle,
/* Now write out each data page, canonicalising page tables as we go... */
while(1)
{
while(1){
unsigned int prev_pc, sent_this_iter, N, batch;
iter++;
@@ -531,15 +515,13 @@ int xc_linux_save(int xc_handle,
prev_pc = 0;
N=0;
verbose_printf("Saving memory pages: iter %d 0%%", iter);
xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter);
while( N < nr_pfns )
{
while( N < nr_pfns ){
unsigned int this_pc = (N * 100) / nr_pfns;
if ( (this_pc - prev_pc) >= 5 )
{
verbose_printf("\b\b\b\b%3d%%", this_pc);
if ( (this_pc - prev_pc) >= 5 ){
xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
prev_pc = this_pc;
}
@@ -549,9 +531,8 @@ int xc_linux_save(int xc_handle,
if ( !last_iter &&
xc_shadow_control(xc_handle, domid,
DOM0_SHADOW_CONTROL_OP_PEEK,
to_skip, nr_pfns, NULL) != nr_pfns )
{
ERROR("Error peeking shadow bitmap");
to_skip, nr_pfns, NULL) != nr_pfns ) {
xcio_error(ioctxt, "Error peeking shadow bitmap");
goto out;
}
@@ -563,23 +544,26 @@ int xc_linux_save(int xc_handle,
{
int n = permute(N, nr_pfns, order_nr );
if ( 0 && debug )
if ( 0 && debug ) {
fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d "
" [mfn]= %08lx\n",
iter, n, live_pfn_to_mfn_table[n],
iter, (unsigned long)n, live_pfn_to_mfn_table[n],
test_bit(n,to_send),
live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&
0xFFFFF]);
}
if ( !last_iter &&
test_bit(n, to_send) &&
test_bit(n, to_skip) )
test_bit(n, to_skip) ) {
skip_this_iter++; /* stats keeping */
}
if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) ||
(test_bit(n, to_send) && last_iter) ||
(test_bit(n, to_fix) && last_iter)) )
(test_bit(n, to_fix) && last_iter)) ) {
continue;
}
/* we get here if:
1. page is marked to_send & hasn't already been re-dirtied
@@ -590,8 +574,7 @@ int xc_linux_save(int xc_handle,
pfn_batch[batch] = n;
pfn_type[batch] = live_pfn_to_mfn_table[n];
if( pfn_type[batch] == 0x80000004 )
{
if( pfn_type[batch] == 0x80000004 ){
/* not currently in pusedo-physical map -- set bit
in to_fix that we must send this page in last_iter
unless its sent sooner anyhow */
@@ -625,22 +608,18 @@ int xc_linux_save(int xc_handle,
if ( (region_base = mfn_mapper_map_batch(xc_handle, domid,
PROT_READ,
pfn_type,
batch)) == 0 )
{
PERROR("map batch failed");
batch)) == 0 ){
xcio_perror(ioctxt, "map batch failed");
goto out;
}
if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) )
{
ERROR("get_pfn_type_batch failed");
if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){
xcio_error(ioctxt, "get_pfn_type_batch failed");
goto out;
}
for ( j = 0; j < batch; j++ )
{
if ( (pfn_type[j] & LTAB_MASK) == XTAB )
{
for ( j = 0; j < batch; j++ ){
if ( (pfn_type[j] & LTAB_MASK) == XTAB ){
DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
continue;
}
@@ -658,39 +637,33 @@ int xc_linux_save(int xc_handle,
pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j];
}
if ( (*writerfn)(writerst, &batch, sizeof(int) ) )
{
ERROR("Error when writing to state file (2)");
if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){
xcio_error(ioctxt, "Error when writing to state file (2)");
goto out;
}
if ( (*writerfn)(writerst, pfn_type, sizeof(unsigned long)*j ) )
{
ERROR("Error when writing to state file (3)");
if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){
xcio_error(ioctxt, "Error when writing to state file (3)");
goto out;
}
/* entering this loop, pfn_type is now in pfns (Not mfns) */
for( j = 0; j < batch; j++ )
{
for( j = 0; j < batch; j++ ){
/* write out pages in batch */
if( (pfn_type[j] & LTAB_MASK) == XTAB)
{
if( (pfn_type[j] & LTAB_MASK) == XTAB){
DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
continue;
}
if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) ||
((pfn_type[j] & LTAB_MASK) == L2TAB) )
{
((pfn_type[j] & LTAB_MASK) == L2TAB) ){
memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
for ( k = 0;
k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ?
(HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) :
1024);
k++ )
{
k++ ){
unsigned long pfn;
if ( !(page[k] & _PAGE_PRESENT) )
@@ -726,20 +699,16 @@ int xc_linux_save(int xc_handle,
} /* end of page table rewrite for loop */
if ( (*writerfn)(writerst, page, PAGE_SIZE) )
{
ERROR("Error when writing to state file (4)");
if ( xcio_write(ioctxt, page, PAGE_SIZE) ){
xcio_error(ioctxt, "Error when writing to state file (4)");
goto out;
}
} /* end of it's a PT page */
else
{ /* normal page */
} /* end of it's a PT page */ else { /* normal page */
if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j),
PAGE_SIZE) )
{
ERROR("Error when writing to state file (5)");
if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j),
PAGE_SIZE) ){
xcio_error(ioctxt, "Error when writing to state file (5)");
goto out;
}
}
@@ -755,37 +724,34 @@ int xc_linux_save(int xc_handle,
total_sent += sent_this_iter;
verbose_printf("\r %d: sent %d, skipped %d, ",
xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ",
iter, sent_this_iter, skip_this_iter );
if ( last_iter )
{
if ( last_iter ) {
print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
verbose_printf("Total pages sent= %d (%.2fx)\n",
xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n",
total_sent, ((float)total_sent)/nr_pfns );
verbose_printf("(of which %d were fixups)\n", needed_to_fix );
xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix );
}
if ( debug && last_iter )
{
if (last_iter && debug){
int minusone = -1;
memset( to_send, 0xff, (nr_pfns+8)/8 );
debug = 0;
printf("Entering debug resend-all mode\n");
/* send "-1" to put receiver into debug mode */
if ( (*writerfn)(writerst, &minusone, sizeof(int)) )
if ( xcio_write(ioctxt, &minusone, sizeof(int)) )
{
ERROR("Error when writing to state file (6)");
xcio_error(ioctxt, "Error when writing to state file (6)");
goto out;
}
continue;
}
if ( last_iter )
break;
if ( last_iter ) break;
if ( live )
{
@@ -805,7 +771,7 @@ int xc_linux_save(int xc_handle,
DOM0_SHADOW_CONTROL_OP_CLEAN2,
to_send, nr_pfns, &stats ) != nr_pfns )
{
ERROR("Error flushing shadow PT");
xcio_error(ioctxt, "Error flushing shadow PT");
goto out;
}
@@ -824,60 +790,51 @@ int xc_linux_save(int xc_handle,
rc = 0;
/* Zero terminate */
if ( (*writerfn)(writerst, &rc, sizeof(int)) )
if ( xcio_write(ioctxt, &rc, sizeof(int)) )
{
ERROR("Error when writing to state file (6)");
xcio_error(ioctxt, "Error when writing to state file (6)");
goto out;
}
/* Get the final execution context */
if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
{
PERROR("Could not get full domain info");
xcio_perror(ioctxt, "Could not get full domain info");
goto out;
}
/* Canonicalise the suspend-record frame number. */
if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) )
{
ERROR("State record is not in range of pseudophys map");
if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){
xcio_error(ioctxt, "State record is not in range of pseudophys map");
goto out;
}
/* Canonicalise each GDT frame number. */
for ( i = 0; i < ctxt.gdt_ents; i += 512 )
{
if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) )
{
ERROR("GDT frame is not in range of pseudophys map");
for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
xcio_error(ioctxt, "GDT frame is not in range of pseudophys map");
goto out;
}
}
/* Canonicalise the page table base pointer. */
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) )
{
ERROR("PT base is not in range of pseudophys map");
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) {
xcio_error(ioctxt, "PT base is not in range of pseudophys map");
goto out;
}
ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] <<
PAGE_SHIFT;
if ( (*writerfn)(writerst, &ctxt, sizeof(ctxt)) ||
(*writerfn)(writerst, live_shinfo, PAGE_SIZE) )
{
ERROR("Error when writing to state file (1)");
if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) ||
xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) {
xcio_error(ioctxt, "Error when writing to state file (1)");
goto out;
}
munmap(live_shinfo, PAGE_SIZE);
out:
if ( pfn_type != NULL )
free(pfn_type);
if ( pfn_type != NULL ) free(pfn_type);
DPRINTF("Save exit rc=%d\n",rc);
return !!rc;
}
+8
View File
@@ -136,6 +136,8 @@ int close_pfn_mapper(int pm_handle);
void *map_pfn_writeable(int pm_handle, unsigned long pfn);
void *map_pfn_readonly(int pm_handle, unsigned long pfn);
void unmap_pfn(int pm_handle, void *vaddr);
int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr);
unsigned long csum_page (void * page);
/*
* MMU updates.
@@ -202,4 +204,10 @@ void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid );
#include "xc_io.h"
int xc_domain_getfullinfo(int xc_handle,
u32 domid,
dom0_op_t *op,
full_execution_context_t *ctxt );
#endif /* __XC_PRIVATE_H__ */
+94 -275
View File
@@ -14,6 +14,8 @@
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "xc_private.h"
#include "gzip_stream.h"
/* Needed for Python versions earlier than 2.3. */
#ifndef PyMODINIT_FUNC
@@ -189,115 +191,35 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
return list;
}
static PyObject *tcp_save(XcObject *xc, u32 dom, char *url, unsigned flags){
#define max_namelen 64
char server[max_namelen];
char *port_s;
int port=777;
int sd = -1;
struct hostent *h;
struct sockaddr_in s;
int sockbufsize;
static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){
int rc = -1;
int writerfn(void *fd, const void *buf, size_t count) {
int tot = 0, rc;
do {
rc = write( (int) fd, ((char*)buf)+tot, count-tot );
if ( rc < 0 ) { perror("WRITE"); return rc; };
tot += rc;
}
while ( tot < count );
return 0;
int fd = -1;
int open_flags = (O_CREAT | O_EXCL | O_WRONLY);
int open_mode = 0644;
printf("%s>\n", __FUNCTION__);
fd = open(state_file, open_flags, open_mode);
if(fd < 0){
xcio_perror(ctxt, "Could not open file for writing");
goto exit;
}
strncpy( server, url+strlen("tcp://"), max_namelen);
server[max_namelen-1]='\0';
if ( (port_s = strchr(server,':')) != NULL ) {
*port_s = '\0';
port = atoi(port_s+1);
/* Compression rate 1: we want speed over compression.
* We're mainly going for those zero pages, after all.
*/
printf("%s>gzip_stream_fdopen... \n", __FUNCTION__);
ctxt->io = gzip_stream_fdopen(fd, "wb1");
if(!ctxt->io){
xcio_perror(ctxt, "Could not allocate compression state");
goto exit;
}
printf("X server=%s port=%d\n",server,port);
h = gethostbyname(server);
sd = socket(AF_INET, SOCK_STREAM,0);
if (sd < 0) goto serr;
s.sin_family = AF_INET;
bcopy ( h->h_addr, &(s.sin_addr.s_addr), h->h_length);
s.sin_port = htons(port);
if ( connect(sd, (struct sockaddr *) &s, sizeof(s)) ) goto serr;
sockbufsize=128*1024;
if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof sockbufsize) < 0 ) goto serr;
if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, (void*)sd) == 0 ) {
if ( read( sd, &rc, sizeof(int) ) != sizeof(int) ) goto serr;
if ( rc == 0 ) {
printf("Migration succesful -- destroy local copy\n");
xc_domain_destroy(xc->xc_handle, dom);
close(sd);
Py_INCREF(zero);
return zero;
} else {
errno = rc;
}
}
serr:
printf("Migration failed -- restart local copy\n");
xc_domain_unpause(xc->xc_handle, dom);
PyErr_SetFromErrno(xc_error);
if ( sd >= 0 ) close(sd);
return NULL;
}
static PyObject *file_save(XcObject *xc, u32 dom, char *state_file, unsigned flags){
int fd = -1;
gzFile gfd = NULL;
int writerfn(void *fd, const void *buf, size_t count) {
int rc;
while ( ((rc = gzwrite( (gzFile*)fd, (void*)buf, count)) == -1) &&
(errno = EINTR) )
continue;
return ! (rc == count);
}
if (strncmp(state_file,"file:",strlen("file:")) == 0){
state_file += strlen("file:");
}
if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 ) {
perror("Could not open file for writing");
goto err;
}
/*
* Compression rate 1: we want speed over compression.
* We're mainly going for those zero pages, after all.
*/
if ( (gfd = gzdopen(fd, "wb1")) == NULL ) {
perror("Could not allocate compression state for state file");
close(fd);
goto err;
}
if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, gfd) == 0 ) {
/* kill domain. We don't want to do this for checkpointing, but
if we don't do it here I think people will hurt themselves
by accident... */
xc_domain_destroy(xc->xc_handle, dom);
gzclose(gfd);
close(fd);
Py_INCREF(zero);
return zero;
}
err:
PyErr_SetFromErrno(xc_error);
if ( gfd != NULL ) gzclose(gfd);
if ( fd >= 0 ) close(fd);
unlink(state_file);
return NULL;
printf("%s> xc_linux_save...\n", __FUNCTION__);
rc = xc_linux_save(xc->xc_handle, ctxt);
exit:
if(ctxt->io) IOStream_close(ctxt->io);
if(fd >= 0) close(fd);
unlink(state_file);
printf("%s> rc=%d\n", __FUNCTION__, rc);
return rc;
}
static PyObject *pyxc_linux_save(PyObject *self,
@@ -306,195 +228,92 @@ static PyObject *pyxc_linux_save(PyObject *self,
{
XcObject *xc = (XcObject *)self;
u32 dom;
u32 dom;
char *state_file;
int progress = 1, live = -1, debug = 0;
int progress = 1, debug = 0;
unsigned int flags = 0;
PyObject *val = NULL;
int rc = -1;
XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
static char *kwd_list[] = { "dom", "state_file", "progress",
"live", "debug", NULL };
static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|iii", kwd_list,
&dom, &state_file, &progress,
&live, &debug) )
if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list,
&ioctxt.domain,
&state_file,
&ioctxt.vmconfig,
&progress,
&debug)){
goto exit;
if (progress) flags |= XCFLAGS_VERBOSE;
if (live == 1) flags |= XCFLAGS_LIVE;
if (debug) flags |= XCFLAGS_DEBUG;
if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 ) {
/* default to live for tcp */
if (live == -1) flags |= XCFLAGS_LIVE;
val = tcp_save(xc, dom, state_file, flags);
} else {
val = file_save(xc, dom, state_file, flags);
}
ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0);
if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
if(!state_file || state_file[0] == '\0') goto exit;
rc = file_save(xc, &ioctxt, state_file);
if(rc){
PyErr_SetFromErrno(xc_error);
goto exit;
}
//xc_domain_destroy(xc->xc_handle, dom);
Py_INCREF(zero);
val = zero;
exit:
return val;
}
static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){
int rc = -1;
ioctxt->io = gzip_stream_fopen(state_file, "rb");
if (!ioctxt->io) {
xcio_perror(ioctxt, "Could not open file for reading");
goto exit;
}
rc = xc_linux_restore(xc->xc_handle, ioctxt);
exit:
if(ioctxt->io) IOStream_close(ioctxt->io);
return rc;
}
static PyObject *pyxc_linux_restore(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
char *state_file;
int progress = 1, debug = 0;
u32 dom;
PyObject *val = NULL;
XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
int rc =-1;
char *state_file;
int progress = 1;
u32 dom;
unsigned int flags = 0;
static char *kwd_list[] = { "state_file", "progress", "debug", NULL };
static char *kwd_list[] = { "dom", "state_file", "progress", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|i", kwd_list,
&dom, &state_file, &progress) )
return NULL;
if ( progress )
flags |= XCFLAGS_VERBOSE;
if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 )
{
#define max_namelen 64
char server[max_namelen];
char *port_s;
int port=777;
int ld = -1, sd = -1;
struct hostent *h;
struct sockaddr_in s, d, p;
socklen_t dlen, plen;
int sockbufsize;
int on = 1, rc = -1;
int readerfn(void *fd, void *buf, size_t count)
{
int rc, tot = 0;
do {
rc = read( (int) fd, ((char*)buf)+tot, count-tot );
if ( rc < 0 ) { perror("READ"); return rc; }
if ( rc == 0 ) { printf("read: need %d, tot=%d got zero\n",
count-tot, tot); return -1; }
tot += rc;
}
while ( tot < count );
return 0;
}
strncpy( server, state_file+strlen("tcp://"), max_namelen);
server[max_namelen-1]='\0';
if ( (port_s = strchr(server,':')) != NULL )
{
*port_s = '\0';
port = atoi(port_s+1);
}
printf("X server=%s port=%d\n",server,port);
h = gethostbyname(server);
ld = socket (AF_INET,SOCK_STREAM,0);
if ( ld < 0 ) goto serr;
s.sin_family = AF_INET;
s.sin_addr.s_addr = htonl(INADDR_ANY);
s.sin_port = htons(port);
if ( setsockopt(ld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0 )
goto serr;
if ( bind(ld, (struct sockaddr *) &s, sizeof(s)) )
goto serr;
if ( listen(ld, 1) )
goto serr;
dlen=sizeof(struct sockaddr);
if ( (sd = accept(ld, (struct sockaddr *) &d, &dlen )) < 0 )
goto serr;
plen = sizeof(p);
if ( getpeername(sd, (struct sockaddr_in *) &p,
&plen) < 0 )
goto serr;
printf("Accepted connection from %s\n", inet_ntoa(p.sin_addr));
sockbufsize=128*1024;
if ( setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
sizeof sockbufsize) < 0 )
goto serr;
rc = xc_linux_restore(xc->xc_handle, dom, flags,
readerfn, (void*)sd, &dom);
write( sd, &rc, sizeof(int) );
if (rc == 0)
{
close(sd);
Py_INCREF(zero);
return zero;
}
errno = rc;
serr:
PyErr_SetFromErrno(xc_error);
if ( ld >= 0 ) close(ld);
if ( sd >= 0 ) close(sd);
return NULL;
}
else
{
int fd = -1;
gzFile gfd = NULL;
int readerfn(void *fd, void *buf, size_t count)
{
int rc;
while ( ((rc = gzread( (gzFile*)fd, (void*)buf, count)) == -1) &&
(errno = EINTR) )
continue;
return ! (rc == count);
}
if ( strncmp(state_file,"file:",strlen("file:")) == 0 )
state_file += strlen("file:");
if ( (fd = open(state_file, O_RDONLY)) == -1 )
{
perror("Could not open file for writing");
goto err;
}
/*
* Compression rate 1: we want speed over compression.
* We're mainly going for those zero pages, after all.
*/
if ( (gfd = gzdopen(fd, "rb")) == NULL )
{
perror("Could not allocate compression state for state file");
close(fd);
goto err;
}
if ( xc_linux_restore(xc->xc_handle, dom, flags,
readerfn, gfd, &dom) == 0 )
{
gzclose(gfd);
close(fd);
Py_INCREF(zero);
return zero;
}
err:
PyErr_SetFromErrno(xc_error);
if ( gfd != NULL ) gzclose(gfd);
if ( fd >= 0 ) close(fd);
return NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list,
&ioctxt.domain,
&state_file,
&progress,
&debug)){
goto exit;
}
if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
if(!state_file || state_file[0] == '\0') goto exit;
rc = file_restore(xc, &ioctxt, state_file);
if(rc){
PyErr_SetFromErrno(xc_error);
goto exit;
}
val = Py_BuildValue("{s:i,s:s}",
"dom", ioctxt.domain,
"vmconfig", ioctxt.vmconfig);
//? free(ioctxt.vmconfig);
exit:
return val;
}
static PyObject *pyxc_linux_build(PyObject *self,
+8 -3
View File
@@ -3,12 +3,17 @@ from distutils.core import setup, Extension
module = Extension("xc",
extra_compile_args = ["-fno-strict-aliasing"],
include_dirs = ["../lib"],
library_dirs = ["../lib"],
include_dirs = ["../lib",
"../../../xen/include/hypervisor-ifs",
"../../../linux-xen-sparse/include",
"../../xu/lib",
"../../lib" ],
library_dirs = ["../lib",
"../../lib" ],
libraries = ["xc"],
sources = ["Xc.c"])
setup(name = "xc",
version = "1.0",
version = "2.0",
ext_package = "xen.ext",
ext_modules = [module])
+12 -9
View File
@@ -9,7 +9,6 @@ import sys
from twisted.internet import defer
import xen.ext.xc; xc = xen.ext.xc.new()
import xenctl.ip
import sxp
import XendRoot
@@ -235,7 +234,7 @@ class XendDomain:
def domain_get(self, id):
id = str(id)
self.refresh_domain(id)
return self.domain[id]
return self.domain.get(id)
def domain_unpause(self, id):
"""(Re)start domain running.
@@ -278,22 +277,26 @@ class XendDomain:
"""
# Need a cancel too?
pass
def domain_save(self, id, dst, progress=0):
"""Save domain state to file, destroy domain.
"""
dom = int(id)
dominfo = self.domain_get(id)
if not dominfo:
return -1
vmconfig = sxp.to_string(dominfo.sxpr())
self.domain_pause(id)
eserver.inject('xend.domain.save', id)
rc = xc.linux_save(dom=dom, state_file=dst, progress=progress)
rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
if rc == 0:
self.domain_destroy(id)
return rc
def domain_restore(self, src, config, progress=0):
def domain_restore(self, src, progress=0):
"""Restore domain from file.
"""
dominfo = XendDomainInfo.dom_restore(dom, config)
dominfo = XendDomainInfo.vm_restore(src, progress=progress)
self._add_domain(dominfo.id, dominfo)
return dominfo
@@ -332,9 +335,9 @@ class XendDomain:
if not dominfo: return None
return dominfo.get_device_by_index(vif)
def domain_vif_ip_add(self, dom, vif, ip):
dom = int(dom)
return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
## def domain_vif_ip_add(self, dom, vif, ip):
## dom = int(dom)
## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
def domain_vbd_ls(self, dom):
dominfo = self.domain_get(dom)
+10 -11
View File
@@ -17,7 +17,7 @@ import os
from twisted.internet import defer
import xen.ext.xc; xc = xen.ext.xc.new()
import xenctl.ip
import xen.util.ip
import sxp
@@ -167,14 +167,14 @@ def vif_up(iplist):
print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
def link_local(ip):
return xenctl.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
def arping(ip, gw):
cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
print cmd
os.system(cmd)
gateway = xenctl.ip.get_current_ipgw() or '255.255.255.255'
gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255'
nlb = get_ip_nonlocal_bind()
if not nlb: set_ip_nonlocal_bind(1)
try:
@@ -272,22 +272,23 @@ def vm_recreate(config, info):
d.callback(vm)
return d
def vm_restore(src, config, progress=0):
def vm_restore(src, progress=0):
"""Restore a VM from a disk image.
src saved state to restore
config configuration
progress progress reporting flag
returns deferred
raises VmError for invalid configuration
"""
vm = XendDomainInfo()
vm.config = config
ostype = "linux" #todo set from config
ostype = "linux" #todo Set from somewhere (store in the src?).
restorefn = getattr(xc, "%s_restore" % ostype)
dom = restorefn(state_file=src, progress=progress)
d = restorefn(state_file=src, progress=progress)
dom = int(d['dom'])
if dom < 0:
raise VMError('restore failed')
vmconfig = sxp.from_string(d['vmconfig'])
vm.config = sxp.child_value(vmconfig, 'config')
deferred = vm.dom_configure(dom)
def vifs_cb(val, vm):
vif_up(vm.ipaddrs)
@@ -855,9 +856,7 @@ def vm_field_vfr(vm, config, val, index):
if not ip:
raise VmError('vfr: missing ip address')
ipaddrs.append(ip);
#Don't do this in new i/o model.
#print 'vm_field_vfr> add rule', 'dom=', vm.dom, 'vif=', vif, 'ip=', ip
#xenctl.ip.setup_vfr_rules_for_vif(vm.dom, vif, ip)
# todo: Configure the ipaddrs.
vm.ipaddrs = ipaddrs
def vnet_bridge(vnet, vmac, dom, idx):
-7
View File
@@ -44,13 +44,6 @@ class SrvDomain(SrvDir):
val = fn(req.args, {'dom': self.dom.id})
return val
def op_restore(self, op, req):
fn = FormFn(self.xd.domain_restore,
[['dom', 'int'],
['file', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
[['dom', 'int'],
+13
View File
@@ -7,6 +7,7 @@ from twisted.web import error
from xen.xend import sxp
from xen.xend import XendDomain
from xen.xend.Args import FormFn
from SrvDir import SrvDir
from SrvDomain import SrvDomain
@@ -88,6 +89,12 @@ class SrvDomainDir(SrvDir):
out.close()
return val
def op_restore(self, op, req):
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
return val
def render_POST(self, req):
return self.perform(req)
@@ -129,3 +136,9 @@ class SrvDomainDir(SrvDir):
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
req.write('Config <input type="file" name="config"><br>')
req.write('</form>')
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
req.write('State <input type="string" name="state"><br>')
req.write('</form>')
+23
View File
@@ -16,6 +16,7 @@ import sys
import types
import errno
import string
from StringIO import StringIO
__all__ = [
"mime_type",
@@ -521,6 +522,28 @@ def elements(sxpr, ctxt=None):
yield v
i += 1
def to_string(sxpr):
"""Convert an sxpr to a string.
sxpr sxpr
returns string
"""
io = StringIO()
show(sxpr, io)
io.seek(0)
val = io.getvalue()
io.close()
return val
def from_string(str):
"""Create an sxpr by parsing a string.
str string
returns sxpr
"""
io = StringIO(str)
return parse(io)
def parse(io):
"""Completely parse all input from 'io'.
+1 -1
View File
@@ -8,7 +8,7 @@ from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend.XendClient import server
from xen.xend.xm.opts import *
from xen.xm.opts import *
gopts = Opts(use="""[options]
+1 -1
View File
@@ -9,7 +9,7 @@ from getopt import getopt
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend.XendClient import server
from xen.xend.xm import create, shutdown
from xen.xm import create, shutdown
class Prog:
"""Base class for sub-programs.
+1
View File
@@ -290,6 +290,7 @@ class Opts:
cmd = '\n'.join(["import sys",
"import os",
"import os.path",
"import xen.util.ip",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help ])
exec cmd in globals, locals
+1 -1
View File
@@ -6,7 +6,7 @@ import sys
import time
from xen.xend.XendClient import server
from xen.xend.xm.opts import *
from xen.xm.opts import *
gopts = Opts(use="""[options] [DOM]
+2 -2
View File
@@ -13,8 +13,8 @@
xend stop
Unfortunately restarting it upsets the channel to dom0 and
domain management stops working - needs a reboot to fix.
The daemon should reconnect to device control interfaces
and recover its state when restarted.
"""
import os
import sys
+1
View File
@@ -4,6 +4,7 @@ CFLAGS = -Wall -O3 -Werror
CFLAGS += -I../../xen/include/hypervisor-ifs
CFLAGS += -I../../linux-xen-sparse/include
CFLAGS += -I../xu/lib
CFLAGS += -I../lib
HDRS = $(wildcard *.h)
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.