diff options
author | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-04-01 23:45:04 +0200 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-04-01 23:45:04 +0200 |
commit | a9b34fd9216367d6f959f979d318b52e00d58118 (patch) | |
tree | e8b6102946183e7625c9253b42d1c605d0658dba | |
parent | b0ea03cb60527efafc317e2623756ff05b90dc19 (diff) | |
download | tsnif-a9b34fd9216367d6f959f979d318b52e00d58118.tar.gz tsnif-a9b34fd9216367d6f959f979d318b52e00d58118.tar.xz tsnif-a9b34fd9216367d6f959f979d318b52e00d58118.zip |
storage support - initial part + test support
-rw-r--r-- | src/Makefile | 17 | ||||
-rw-r--r-- | src/storage-mmap.c | 265 | ||||
-rw-r--r-- | src/storage-mmap.h | 47 | ||||
-rw-r--r-- | src/storage.h | 45 | ||||
-rw-r--r-- | src/test-storage-mmap.c | 40 | ||||
-rw-r--r-- | src/test.c | 30 | ||||
-rw-r--r-- | src/test.h | 20 | ||||
-rw-r--r-- | src/trans.h | 1 | ||||
-rw-r--r-- | src/tsnif.c | 60 |
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); } |