summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-04-01 23:45:04 +0200
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-04-01 23:45:04 +0200
commita9b34fd9216367d6f959f979d318b52e00d58118 (patch)
treee8b6102946183e7625c9253b42d1c605d0658dba
parentb0ea03cb60527efafc317e2623756ff05b90dc19 (diff)
downloadtsnif-a9b34fd9216367d6f959f979d318b52e00d58118.tar.gz
tsnif-a9b34fd9216367d6f959f979d318b52e00d58118.tar.xz
tsnif-a9b34fd9216367d6f959f979d318b52e00d58118.zip
storage support - initial part + test support
-rw-r--r--src/Makefile17
-rw-r--r--src/storage-mmap.c265
-rw-r--r--src/storage-mmap.h47
-rw-r--r--src/storage.h45
-rw-r--r--src/test-storage-mmap.c40
-rw-r--r--src/test.c30
-rw-r--r--src/test.h20
-rw-r--r--src/trans.h1
-rw-r--r--src/tsnif.c60
9 files changed, 514 insertions, 11 deletions
diff --git a/src/Makefile b/src/Makefile
index a0543e4..2809eb4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,7 +5,7 @@ INTF_OBJS= \
src/trans-libnl.o
STORAGE_OBJS= \
- src/storage.o
+ src/storage-mmap.o
INTF_LIB=-lnl
@@ -39,6 +39,15 @@ SIMPTY_OBJS= \
$(SIMPTY): $(SIMPTY_OBJS)
$(QUIET_LD)$(CC) -o $@ $^
+TEST=tsnif-test
+TEST_OBJS=\
+ src/test.o \
+ src/test-storage-mmap.o \
+ $(STORAGE_OBJS)
+
+$(TEST): $(TEST_OBJS)
+ $(QUIET_LD)$(CC) -o $@ $^
+
OBJS= \
$(INTF_OBJS) \
@@ -46,13 +55,15 @@ OBJS= \
$(TSNIF_OBJS) \
$(TSNIF_REPLAY_OBJS) \
$(TSNIFD_OBJS) \
- $(SIMPTY_OBJS)
+ $(SIMPTY_OBJS) \
+ $(TEST_OBJS)
PROGRAMS= \
$(TSNIF) \
$(TSNIF_REPLAY) \
$(TSNIFD) \
- $(SIMPTY)
+ $(SIMPTY) \
+ $(TEST)
install::
$(call install,$(TSNIF),$(bindir),"rx")
diff --git a/src/storage-mmap.c b/src/storage-mmap.c
new file mode 100644
index 0000000..23fb720
--- /dev/null
+++ b/src/storage-mmap.c
@@ -0,0 +1,265 @@
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <asm/errno.h>
+#include <errno.h>
+
+#include "storage.h"
+#include "intf.h"
+
+static int unmap_chunk(struct tsnif_storage_handle *h,
+ struct tsnif_storage_chunk *chunk);
+
+static int write_header(int fd, struct tsnif_storage_opts *opts)
+{
+ int err;
+
+ struct tsnif_storage_header_mmap header = {
+ .common = {
+ .magic = TSNIF_HEADER_MAGIC,
+ .type = TSNIF_STORAGE_TYPE_MMAP,
+ },
+ .size_max = opts->size_max,
+ };
+
+ err = write(fd, &header, sizeof(header));
+ if (err < 0)
+ return err;
+
+ return ftruncate(fd, sysconf(_SC_PAGESIZE));
+}
+
+static int map_header(struct tsnif_storage_handle *h)
+{
+ void *ptr;
+
+ ptr = mmap(NULL, sysconf(_SC_PAGESIZE),
+ PROT_WRITE | PROT_READ,
+ MAP_SHARED, h->fd, 0);
+ if (MAP_FAILED == ptr)
+ return -1;
+
+ h->header = ptr;
+ return 0;
+}
+
+int tsnif_storage_init(struct tsnif_storage_handle *h,
+ struct tsnif_storage_opts *opts, char *name)
+{
+ int fd, create, err;
+ int flags = O_RDWR;
+
+ if (!opts)
+ return -1;
+
+ memset(h, 0, sizeof(*h));
+ h->opts = opts;
+
+ /* mmap page sized chunks as default */
+ if (!opts->chunk_size)
+ opts->chunk_size = sysconf(_SC_PAGESIZE);
+
+ create = (opts->flags & TSNIF_STORAGE_OPT_CREATE);
+ if (create)
+ flags |= O_CREAT | O_TRUNC;
+
+ fd = open(name, flags, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ TSNIF_DEBUG("open failed for '%s': %s\n",
+ name, strerror(errno));
+ return -1;
+ }
+
+ TSNIF_DEBUG("opened '%s'\n", name);
+
+ if (create &&
+ (err = write_header(fd, opts))) {
+ TSNIF_DEBUG("write failed for '%s': %s\n",
+ name, strerror(errno));
+ close(fd);
+ return err;
+ }
+
+ h->fd = fd;
+
+ err = map_header(h);
+ if (err) {
+ close(fd);
+ return err;
+ }
+
+ return 0;
+}
+
+int tsnif_storage_close(struct tsnif_storage_handle *h)
+{
+ if (h->header)
+ munmap(h->header, sysconf(_SC_PAGESIZE));
+
+ unmap_chunk(h, &h->active_chunk);
+
+ close(h->fd);
+ return 0;
+}
+
+static int get_open_offset(struct tsnif_storage_handle *h)
+{
+ return 0;
+}
+
+static int unmap_chunk(struct tsnif_storage_handle *h,
+ struct tsnif_storage_chunk *chunk)
+{
+ if (!chunk->header)
+ return -1;
+
+ return munmap(chunk->header, h->opts->chunk_size);
+}
+
+enum {
+ STORAGE_MMAP_FIRST,
+ STORAGE_MMAP_NEXT,
+};
+
+static int file_trunc(struct tsnif_storage_handle *h, off_t new_size)
+{
+ off_t size;
+
+ size = lseek(h->fd, 0, SEEK_END);
+ if (size < 0)
+ return -1;
+
+ if (size >= new_size)
+ return 0;
+
+ return ftruncate(h->fd, new_size);
+}
+
+static int map_chunk(struct tsnif_storage_handle *h,
+ struct tsnif_storage_chunk *chunk, int what)
+{
+ void *ptr;
+ off_t offset;
+ int err;
+
+ if (what == STORAGE_MMAP_FIRST) {
+ offset = sysconf(_SC_PAGESIZE);
+
+ if (h->opts->flags & TSNIF_STORAGE_OPT_OPEN)
+ offset = get_open_offset(h);
+ }
+
+ if (what == STORAGE_MMAP_NEXT) {
+
+ offset = chunk->offset +
+ h->opts->chunk_size +
+ sysconf(_SC_PAGESIZE);
+
+ if (offset > h->opts->size_max)
+ offset = sysconf(_SC_PAGESIZE);
+ }
+
+ if (chunk->header)
+ unmap_chunk(h, chunk);
+
+ err = file_trunc(h, offset);
+ if (err)
+ return err;
+
+ ptr = mmap(NULL, h->opts->chunk_size,
+ PROT_WRITE | PROT_READ,
+ MAP_SHARED, h->fd, offset);
+ if (MAP_FAILED == ptr)
+ return -1;
+
+ chunk->offset = offset;
+ return 0;
+}
+
+static int clear_chunk(struct tsnif_storage_handle *h,
+ struct tsnif_storage_chunk *chunk)
+{
+ struct tsnif_storage_chunk_header *header = chunk->header;
+
+ memset(header, 0x0, sizeof(*header));
+ header->free = h->opts->chunk_size -
+ sizeof(struct tsnif_storage_chunk_header);
+
+ chunk->current_data = header->rec0;
+ chunk->current_index = (uint32_t*) (chunk->header + h->opts->chunk_size
+ - sizeof(uint32_t));
+ return 0;
+}
+
+static int map_write_chunk(struct tsnif_storage_handle *h,
+ struct tsnif_storage_chunk *chunk, int what)
+{
+ return (map_chunk(h, chunk, what) ||
+ clear_chunk(h, chunk));
+}
+
+static int get_chunk_rec(struct tsnif_storage_handle *h, int size)
+{
+ struct tsnif_storage_chunk *chunk = &h->active_chunk;
+ struct tsnif_storage_chunk_header *chunk_header = chunk->header;
+
+ /* first time */
+ if (!chunk_header)
+ return map_write_chunk(h, chunk, STORAGE_MMAP_FIRST);
+
+ /* we fit into current chunk */
+#define INDEX_OVERHEAD (4*sizeof(uint32_t))
+ if (chunk_header->free > (size +
+ sizeof(struct tsnif_storage_rec_mmap) +
+ INDEX_OVERHEAD))
+ return 0;
+
+ /* we dont fit into current chunk,
+ * let's go for another */
+ return map_write_chunk(h, chunk, STORAGE_MMAP_NEXT);
+}
+
+static int store_rec(struct tsnif_storage_handle *h,
+ struct tsnif_storage_rec *rec)
+{
+ struct tsnif_storage_rec_mmap *mrec;
+ struct tsnif_storage_chunk *chunk = &h->active_chunk;
+ struct tsnif_storage_chunk_header *header = chunk->header;
+
+ mrec = chunk->current_data;
+ mrec->len = rec->len;
+ mrec->flags = rec->flags;
+ memcpy(mrec->data, rec->ptr, rec->len);
+
+#define RECLEN (sizeof(struct tsnif_storage_rec_mmap) + rec->len)
+
+ *(chunk->current_index) = (void*) chunk->current_data - (void*) mrec;
+ chunk->current_index--;
+ chunk->current_data += RECLEN;
+
+ header->cnt++;
+ header->free -= (sizeof(uint32_t) + RECLEN);
+ return 0;
+}
+
+int tsnif_storage_write(struct tsnif_storage_handle *h,
+ struct tsnif_storage_rec *rec)
+{
+ int err;
+
+ err = get_chunk_rec(h, rec->len);
+ if (err)
+ return err;
+
+ return store_rec(h, rec);
+}
+
+int tsnif_storage_read(struct tsnif_storage_handle *h, int idx,
+ struct tsnif_storage_rec *rec)
+{
+ return 0;
+}
diff --git a/src/storage-mmap.h b/src/storage-mmap.h
new file mode 100644
index 0000000..c05bbd0
--- /dev/null
+++ b/src/storage-mmap.h
@@ -0,0 +1,47 @@
+
+#ifndef STORAGE_MMAP_H
+#define STORAGE_MMAP_H
+
+struct tsnif_storage_header_mmap {
+ struct tsnif_storage_header common;
+ uint32_t size_max;
+ uint32_t cnt;
+};
+
+struct tsnif_storage_rec_mmap {
+ uint32_t len;
+ uint32_t flags;
+ unsigned char data[];
+};
+
+struct tsnif_storage_chunk_header {
+ uint32_t free;
+ uint32_t cnt;
+ unsigned char rec0[];
+};
+
+struct tsnif_storage_opts {
+ int size_max;
+ uint flags;
+ int chunk_size;
+};
+
+struct tsnif_storage_chunk {
+ struct tsnif_storage_chunk_header *header;
+ off_t offset;
+ void *current_data;
+ uint32_t *current_index;
+};
+
+struct tsnif_storage_handle {
+ int fd;
+ struct tsnif_storage_opts *opts;
+
+ /* file header */
+ struct tsnif_storage_header_mmap *header;
+
+ /* active chunk */
+ struct tsnif_storage_chunk active_chunk;
+};
+
+#endif /* STORAGE_MMAP_H */
diff --git a/src/storage.h b/src/storage.h
new file mode 100644
index 0000000..00826d8
--- /dev/null
+++ b/src/storage.h
@@ -0,0 +1,45 @@
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+struct tsnif_storage_handle;
+struct tsnif_storage_opts;
+
+enum {
+ TSNIF_STORAGE_TYPE_MMAP,
+};
+
+#define TSNIF_HEADER_MAGIC 0xdeadfeed
+
+struct tsnif_storage_header {
+ uint32_t magic;
+ uint32_t type;
+};
+
+enum {
+ TSNIF_STORAGE_OPT_CREATE = 0x1,
+ TSNIF_STORAGE_OPT_OPEN = 0x2,
+ TSNIF_STORAGE_OPT_READ = 0x4,
+ TSNIF_STORAGE_OPT_WRITE = 0x8,
+};
+
+struct tsnif_storage_rec {
+ void *ptr;
+ int len;
+ uint flags;
+};
+
+int tsnif_storage_init(struct tsnif_storage_handle *h,
+ struct tsnif_storage_opts *ops, char *name);
+int tsnif_storage_close(struct tsnif_storage_handle *h);
+int tsnif_storage_write(struct tsnif_storage_handle *h,
+ struct tsnif_storage_rec *rec);
+int tsnif_storage_read(struct tsnif_storage_handle *h, int idx,
+ struct tsnif_storage_rec *rec);
+
+/* TODO make CONFIG option and ifdef this place */
+#include "storage-mmap.h"
+
+#endif /* STORAGE_H */
diff --git a/src/test-storage-mmap.c b/src/test-storage-mmap.c
new file mode 100644
index 0000000..64c9044
--- /dev/null
+++ b/src/test-storage-mmap.c
@@ -0,0 +1,40 @@
+
+#include <stdio.h>
+#include "test.h"
+#include "storage.h"
+
+#define FILENAME "/tmp/tsnif-storage-mmap.tsnif"
+
+int tsnif_debug = 0;
+
+int test_storage_mmap_init(void)
+{
+ int rc = 0;
+ struct tsnif_storage_handle handle;
+ struct tsnif_storage_opts opts = {
+ .flags = TSNIF_STORAGE_OPT_CREATE | TSNIF_STORAGE_OPT_WRITE,
+ .size_max = 1024*1024,
+ };
+
+ TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out);
+ TEST_ASSERT(0 == tsnif_storage_close(&handle), out);
+
+out:
+ return rc;
+}
+
+int test_storage_mmap_write(void)
+{
+ int rc = 0;
+ struct tsnif_storage_handle handle;
+ struct tsnif_storage_opts opts = {
+ .flags = TSNIF_STORAGE_OPT_CREATE | TSNIF_STORAGE_OPT_WRITE,
+ .size_max = 1024*1024,
+ };
+
+ TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out);
+ TEST_ASSERT(0 == tsnif_storage_close(&handle), out);
+
+out:
+ return rc;
+}
diff --git a/src/test.c b/src/test.c
new file mode 100644
index 0000000..0bd2f10
--- /dev/null
+++ b/src/test.c
@@ -0,0 +1,30 @@
+
+#include <stdio.h>
+
+#define TEST_RUN(test) \
+do { \
+ printf("RUNNING " # test "\n"); \
+ if ((test())) { \
+ overall_ok = 0; \
+ printf("FAILED test " # test "\n"); \
+ } \
+ printf("\n"); \
+} while(0)
+
+int test_storage_mmap_init(void);
+int test_storage_mmap_write(void);
+
+int main(int argc, char **argv)
+{
+ int overall_ok = 1;
+
+ TEST_RUN(test_storage_mmap_init);
+ TEST_RUN(test_storage_mmap_write);
+
+ if (overall_ok)
+ printf("PASSED\n");
+ else
+ printf("FAILED\n");
+
+ return overall_ok ? 0 : -1;
+}
diff --git a/src/test.h b/src/test.h
new file mode 100644
index 0000000..a1f89ce
--- /dev/null
+++ b/src/test.h
@@ -0,0 +1,20 @@
+
+#ifndef TEST_H
+#define TEST_H
+
+#include <stdio.h>
+
+#define TEST_ASSERT(cond, out_label) \
+do { \
+ printf(" ASSERT '" #cond "' ... "); \
+ if (!(cond)) { \
+ rc = -1; \
+ printf("FAILED\n"); \
+ printf(" ^^^^^^ %s:%d function %s\n",\
+ __FILE__, __LINE__, __FUNCTION__); \
+ goto out_label; \
+ } \
+ printf("OK\n"); \
+} while(0)
+
+#endif /* TEST_H */
diff --git a/src/trans.h b/src/trans.h
index 4778695..95b4457 100644
--- a/src/trans.h
+++ b/src/trans.h
@@ -43,6 +43,7 @@ int trans_send(struct trans_handle *h, struct trans_msg *msg);
int trans_group(struct trans_handle *h, int group);
int trans_fd(struct trans_handle *h);
+/* TODO make CONFIG option and ifdef this place */
#include "trans-libnl.h"
#endif /* !TRANS_H */
diff --git a/src/tsnif.c b/src/tsnif.c
index b6f4150..102d2d2 100644
--- a/src/tsnif.c
+++ b/src/tsnif.c
@@ -10,15 +10,25 @@
#include "autoconf.h"
#include "intf.h"
+#include "storage.h"
-struct tsnif_handle handle;
-struct tsnif_term term;
+
+static struct tsnif_handle handle;
+static struct tsnif_term term;
+
+static struct tsnif_storage_opts storage_opts = {
+ .flags = TSNIF_STORAGE_OPT_CREATE | TSNIF_STORAGE_OPT_WRITE,
+ .size_max = 1024*1024,
+};
+static struct tsnif_storage_handle storage_handle;
static int killed = 0;
+static int store = 0;
static int type = -1;
static int idx = -1;
static int display_slave = 1;
static int display_master = 0;
+static char *storage_file = NULL;
static int display_pty(int flags)
{
@@ -33,6 +43,17 @@ static int display_pty(int flags)
return 1;
}
+static int store_data(struct tsnif_data *data)
+{
+ struct tsnif_storage_rec rec = {
+ .ptr = data->ptr,
+ .len = data->len,
+ .flags = data->flags,
+ };
+
+ return tsnif_storage_write(&storage_handle, &rec);
+}
+
static int data_cb(struct tsnif_term* term, struct tsnif_data *data)
{
/* rule out unwanted PTY channel */
@@ -42,6 +63,10 @@ static int data_cb(struct tsnif_term* term, struct tsnif_data *data)
fwrite(data->ptr, data->len, 1, stdout);
fflush(NULL);
+
+ if (store)
+ return store_data(data);
+
return 0;
}
@@ -69,7 +94,7 @@ struct tsnif_ops ops = {
static void usage()
{
- printf("tsnif -t <terminal type> -i <terminal index>\n");
+ printf("tsnif -t <terminal type> -i <terminal index> [ -s<file> ]\n");
printf(" where types can be 'tty', 'ttys' or 'pty'\n");
_exit(-1);
}
@@ -118,13 +143,14 @@ static int get_args(int argc, char **argv)
static struct option long_options[] = {
{"type", required_argument, 0, 't'},
{"idx", required_argument, 0, 'i'},
+ {"store", required_argument, 0, 's'},
{"version", no_argument, 0, 'v'},
{"debug", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "t:i:vdh",
+ c = getopt_long(argc, argv, "t:i:s:vdh",
long_options, &option_index);
if (c == -1)
@@ -147,6 +173,11 @@ static int get_args(int argc, char **argv)
}
break;
+ case 's':
+ storage_file = optarg;
+ store = 1;
+ break;
+
case 'v':
printf("tsnif "CONFIG_TSNIF_VER"\n");
break;
@@ -208,9 +239,14 @@ int main(int argc, char **argv)
return err;
if ((ret = setjmp(env))) {
+ if (ret > 2) {
+ set_term(1);
+ if (store)
+ tsnif_storage_close(&storage_handle);
+ }
+
if (ret > 1) {
tsnif_detach(&term);
- set_term(1);
}
tsnif_close(&handle);
@@ -218,6 +254,7 @@ int main(int argc, char **argv)
return err;
}
+ /* attach the term */
err = tsnif_term_add(&handle, &term, type, idx);
if (err)
longjmp(env, 1);
@@ -226,6 +263,13 @@ int main(int argc, char **argv)
if (err)
longjmp(env, 1);
+ /* initialize storage unit if needed */
+ if (store) {
+ err = tsnif_storage_init(&storage_handle, &storage_opts, storage_file);
+ if (err)
+ longjmp(env, 2);
+ }
+
set_term(0);
signal(SIGINT, sig_handler);
@@ -248,12 +292,12 @@ int main(int argc, char **argv)
if (FD_ISSET(ts_fd, &rfds) &&
tsnif_process(&handle))
- longjmp(env, 2);
+ longjmp(env, 3);
if (FD_ISSET(in_fd, &rfds) &&
process_input())
- longjmp(env, 2);
+ longjmp(env, 3);
}
- longjmp(env, 2);
+ longjmp(env, 3);
}