[master] a099300 Beginnings of new VSL api

Martin Blix Grydeland martin at varnish-cache.org
Wed May 15 14:46:14 CEST 2013


commit a0993006bb06c3684847057bd3dc692f2d03c04f
Author: Martin Blix Grydeland <martin at varnish-software.com>
Date:   Wed Apr 10 13:47:39 2013 +0200

    Beginnings of new VSL api
    
    Remove automagic reopening logic from vsl
    
    Make vsl use the new VSL_head structure
    
    Remove most of the old functionality

diff --git a/include/vapi/vsl.h b/include/vapi/vsl.h
index db8b953..6ee0e33 100644
--- a/include/vapi/vsl.h
+++ b/include/vapi/vsl.h
@@ -28,131 +28,129 @@
  *
  * This is the public API for the VSL access.
  *
- * VSL is a "subclass" of VSM.
- *
- * VSL can either read from VSM or from a file.
- *
- * When reading from a file, the filename is passed in with:
- *	VSL_Arg(vd, "r", "/some/file");
- * and once VSL_Dispatch()/VSL_NextSLT() will indicate EOF by returning -2.
- * Another file can then be opened with VSL_Arg() and processed.
- *
  */
 
 #ifndef VAPI_VSL_H_INCLUDED
 #define VAPI_VSL_H_INCLUDED
 
-#include "vapi/vsl_int.h"
+#include <stdio.h>
 
-struct VSM_data;
+#include "vapi/vsm.h"
+#include "vapi/vsl_int.h"
 
-/*---------------------------------------------------------------------
- * VSL level access functions
- */
+#define VSL_ARGS	"i:x:"
 
-#define VSL_ARGS	"bCcdI:i:k:n:r:s:X:x:m:"
-#define VSL_b_USAGE	"[-b]"
-#define VSL_c_USAGE	"[-c]"
-#define VSL_C_USAGE	"[-C]"
-#define VSL_d_USAGE	"[-d]"
 #define VSL_i_USAGE	"[-i tag]"
-#define VSL_I_USAGE	"[-I regexp]"
-#define VSL_k_USAGE	"[-k keep]"
-#define VSL_m_USAGE	"[-m tag:regex]"
-#define VSL_n_USAGE	VSM_n_USAGE
-#define VSL_r_USAGE	"[-r file]"
-#define VSL_s_USAGE	"[-s skip]"
 #define VSL_x_USAGE	"[-x tag]"
-#define VSL_X_USAGE	"[-X regexp]"
 
-#define VSL_USAGE	"[-bCcd] "		\
+#define VSL_USAGE	"[...] "		\
 			VSL_i_USAGE " "		\
-			VSL_I_USAGE " "		\
-			VSL_k_USAGE " "		\
-			VSL_m_USAGE " "		\
-			VSL_n_USAGE " "		\
-			VSL_r_USAGE " "		\
-			VSL_s_USAGE " "		\
-			VSL_X_USAGE " "		\
 			VSL_x_USAGE
 
-int VSL_Arg(struct VSM_data *vd, int arg, const char *opt);
+struct VSL_data;
+
+struct VSL_cursor {
+	const uint32_t		*ptr; /* Record pointer */
+};
+
+extern const char *VSL_tags[256];
+	/*
+	 * Tag to string array.  Contains NULL for invalid tags.
+	 */
+
+int VSL_Name2Tag(const char *name, int l);
+	/*
+	 * Convert string to tag number (= enum VSL_tag_e)
+	 *
+	 * Return values:
+	 *	>=0:	Tag number
+	 *	-1:	No tag matches
+	 *	-2:	Multiple tags match substring
+	 */
+
+struct VSL_data *VSL_New(void);
+int VSL_Arg(struct VSL_data *vsl, int opt, const char *arg);
 	/*
 	 * Handle standard log-presenter arguments
 	 * Return:
-	 *	-1 error, VSM_Error() returns diagnostic string
+	 *	-1 error, VSL_Error() returns diagnostic string
 	 *	 0 not handled
 	 *	 1 Handled.
 	 */
 
-typedef int VSL_handler_f(void *priv, enum VSL_tag_e tag, unsigned fd,
-    unsigned len, unsigned spec, const char *ptr, uint64_t bitmap);
+void VSL_Delete(struct VSL_data *vsl);
 	/*
-	 * This is the call-back function you must provide.
-	 *	priv is whatever you asked for it to be.
-	 *	tag is the SLT_mumble tag
-	 *	fd is the filedescriptor associated with this record
-	 *	len is the length of the data at ptr
-	 *	spec are the VSL_S_* flags
-	 *	ptr points to the data, beware of non-printables.
-	 *	bitmap is XXX ???
+	 * Delete a VSL context, freeing up the resources
 	 */
 
-#define VSL_S_CLIENT	(1 << 0)
-#define VSL_S_BACKEND	(1 << 1)
-
-VSL_handler_f VSL_H_Print;
+const char *VSL_Error(const struct VSL_data *vsl);
 	/*
-	 * This call-back function will printf() the record to the FILE *
-	 * specified in priv.
+	 * Return the latest error message.
 	 */
 
-void VSL_Select(struct VSM_data *vd, enum VSL_tag_e tag);
+void VSL_ResetError(struct VSL_data *vsl);
 	/*
-	 * This adds tags which shall always be selected, similar to using
-	 * the '-i' option.
-	 * VSL_Select()/-i takes precedence over all other filtering.
+	 * Reset any error message.
 	 */
 
-int VSL_Dispatch(struct VSM_data *vd, VSL_handler_f *func, void *priv);
+struct VSL_cursor *VSL_CursorVSM(struct VSL_data *vsl, struct VSM_data *vsm,
+    int tail);
+       /*
+        * Set the cursor pointed to by cursor up as a raw cursor in the
+        * log. If tail is non-zero, it will point to the tail of the
+        * log. Is tail is zero, it will point close to the head of the
+        * log, at least 2 segments away from the head.
+	*
+	* Return values:
+	* non-NULL: Pointer to cursor
+	*     NULL: Error, see VSL_Error
+        */
+
+struct VSL_cursor *VSL_CursorFile(struct VSL_data *vsl, const char *name);
 	/*
-	 * Call func(priv, ...) for all filtered VSL records.
+	 * Create a cursor pointing to the beginning of the binary VSL log
+	 * in file name. If name is '-' reads from stdin.
 	 *
 	 * Return values:
-	 *	!=0:	Non-zero return value from func()
-	 *	0:	no VSL records.
-	 *	-1:	VSL chunk was abandoned.
-	 *	-2:	End of file (-r) / -k arg exhausted / "done"
+	 * non-NULL: Pointer to cursor
+	 *     NULL: Error, see VSL_Error
 	 */
 
-int VSL_NextSLT(struct VSM_data *lh, uint32_t **pp, uint64_t *bitmap);
+void VSL_DeleteCursor(struct VSL_cursor *c);
 	/*
-	 * Return raw pointer to next filtered VSL record.
-	 *
-	 * Return values:
-	 *	1:	Valid VSL record at *pp
-	 *	0:	no VSL records
-	 *	-1:	VSL chunk was abandoned
-	 *	-2:	End of file (-r) / -k arg exhausted / "done"
+	 * Delete the cursor pointed to by c
 	 */
 
-int VSL_Matched(struct VSM_data *vd, uint64_t bitmap);
+int VSL_Next(struct VSL_cursor *c);
 	/*
+	 * Return raw pointer to next VSL record.
+	 *
+	 * Return values:
+	 *	1:	Cursor points to next log record
+	 *	0:	End of log
+	 *     -1:	End of file (-r) (XXX / -k arg exhausted / "done")
+	 *     -2:	Remote abandoned or closed
+	 *     -3:	Overrun
+	 *     -4:	I/O read error - see errno
 	 */
 
-int VSL_Name2Tag(const char *name, int l);
+int VSL_Match(struct VSL_data *vsl, const struct VSL_cursor *c);
 	/*
-	 * Convert string to tag number (= enum VSL_tag_e)
+	 * Returns true if the record pointed to by cursor matches the
+	 * record current record selectors
 	 *
-	 * Return values:
-	 *	>=0:	Tag number
-	 *	-1:	No tag matches
-	 *	-2:	Multiple tags match substring
+	 * Return value:
+	 *	1:	Match
+	 *	0:	No match
 	 */
 
-extern const char *VSL_tags[256];
+int VSL_Print(struct VSL_data *vsl, const struct VSL_cursor *c, void *file);
 	/*
-	 * Tag to string array.  Contains NULL for invalid tags.
+	 * Print the log record pointed to by cursor to stream.
+	 *
+	 * Return values:
+	 *	0:	OK
+	 *     -5:	I/O write error - see errno
 	 */
 
 #endif /* VAPI_VSL_H_INCLUDED */
diff --git a/include/vapi/vsl_int.h b/include/vapi/vsl_int.h
index c34706b..c42198a 100644
--- a/include/vapi/vsl_int.h
+++ b/include/vapi/vsl_int.h
@@ -88,6 +88,7 @@ struct VSL_head {
 #define VSL_CLIENT(ptr)		(((ptr)[1]) & VSL_CLIENTMARKER)
 #define VSL_BACKEND(ptr)	(((ptr)[1]) & VSL_BACKENDMARKER)
 #define VSL_DATA(ptr)		((char*)((ptr)+2))
+#define VSL_CDATA(ptr)		((const char*)((ptr)+2))
 
 #define VSL_ENDMARKER	(((uint32_t)SLT__Reserved << 24) | 0x454545) /* "EEE" */
 #define VSL_WRAPMARKER	(((uint32_t)SLT__Reserved << 24) | 0x575757) /* "WWW" */
diff --git a/include/vapi/vsm.h b/include/vapi/vsm.h
index c405168..f6f7f9e 100644
--- a/include/vapi/vsm.h
+++ b/include/vapi/vsm.h
@@ -148,7 +148,8 @@ int VSM_StillValid(const struct VSM_data *vd, struct VSM_fantom *vf);
 	 * Return:
 	 *	0: fantom is not valid any more.
 	 *	1: fantom is still the same.
-	 *	2: a fantom with same dimensions exist, check class/type/ident
+	 *	2: a fantom with same dimensions exist in same position,
+	 *	   check class/type/ident
 	 */
 
 int VSM_Get(const struct VSM_data *vd, struct VSM_fantom *vf,
diff --git a/lib/libvarnishapi/Makefile.am b/lib/libvarnishapi/Makefile.am
index 2e5de91..6069534 100644
--- a/lib/libvarnishapi/Makefile.am
+++ b/lib/libvarnishapi/Makefile.am
@@ -26,6 +26,7 @@ libvarnishapi_la_SOURCES = \
 	../libvarnish/vsha256.c \
 	vsm.c \
 	vsl_arg.c \
+	vsl_cursor.c \
 	vsl.c \
 	vsc.c \
 	libvarnishapi.map
diff --git a/lib/libvarnishapi/libvarnishapi.map b/lib/libvarnishapi/libvarnishapi.map
index 34a851d..a25aa94 100644
--- a/lib/libvarnishapi/libvarnishapi.map
+++ b/lib/libvarnishapi/libvarnishapi.map
@@ -95,5 +95,15 @@ LIBVARNISHAPI_1.3 {
 	VSC_MainValid;
 	VSC_IterValid;
 	VSC_LevelDesc;
+	VSL_New;
+	VSL_Delete;
+	VSL_Error;
+	VSL_ResetError;
+	VSL_CursorVSM;
+	VSL_CursorFile;
+	VSL_DeleteCursor;
+	VSL_Next;
+	VSL_Match;
+	VSL_Print;
 	# Variables:
 } LIBVARNISHAPI_1.0;
diff --git a/lib/libvarnishapi/vsl.c b/lib/libvarnishapi/vsl.c
index cb9e6eb..963afce 100644
--- a/lib/libvarnishapi/vsl.c
+++ b/lib/libvarnishapi/vsl.c
@@ -1,9 +1,10 @@
 /*-
  * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
+ * Copyright (c) 2006-2013 Varnish Software AS
  * All rights reserved.
  *
  * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +34,7 @@
 #include <sys/types.h>
 
 #include <errno.h>
+#include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,12 +45,14 @@
 #include "vas.h"
 #include "vdef.h"
 
-#include "vapi/vsl.h"
 #include "vapi/vsm.h"
+#include "vapi/vsl.h"
 #include "vapi/vsm_int.h"
+#include "vin.h"
 #include "vbm.h"
 #include "vmb.h"
 #include "vre.h"
+#include "vsb.h"
 #include "vsl_api.h"
 #include "vsm_api.h"
 
@@ -60,334 +64,139 @@ const char *VSL_tags[256] = {
 #  undef SLTM
 };
 
-/*--------------------------------------------------------------------*/
-
-struct vsl *
-vsl_Setup(struct VSM_data *vd)
+int
+vsl_diag(struct VSL_data *vsl, const char *fmt, ...)
 {
-	struct vsl *vsl;
+	va_list ap;
 
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-	if (vd->vsl == NULL) {
-		ALLOC_OBJ(vd->vsl, VSL_MAGIC);
-		AN(vd->vsl);
-		vsl = vd->vsl;
-		vsl->regflags = 0;
-		vsl->vbm_supress = vbit_init(256);
-		vsl->vbm_select = vbit_init(256);
-		vsl->r_fd = -1;
-		vsl->num_matchers = 0;
-		VTAILQ_INIT(&vsl->matchers);
-	}
-	CHECK_OBJ_NOTNULL(vd->vsl, VSL_MAGIC);
-	return (vd->vsl);
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
+	AN(fmt);
+
+	if (vsl->diag == NULL)
+		vsl->diag = VSB_new_auto();
+	AN(vsl->diag);
+	VSB_clear(vsl->diag);
+	va_start(ap, fmt);
+	VSB_vprintf(vsl->diag, fmt, ap);
+	va_end(ap);
+	AZ(VSB_finish(vsl->diag));
+	return (-1);
 }
 
-/*--------------------------------------------------------------------
- * Called from VSM_Delete()
- */
-
-void
-VSL_Delete(struct VSM_data *vd)
+struct VSL_data *
+VSL_New(void)
 {
-	struct vsl *vsl;
+	struct VSL_data *vsl;
 
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-	vsl = vd->vsl;
-	vd->vsl = NULL;
-	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
+	ALLOC_OBJ(vsl, VSL_MAGIC);
+	if (vsl == NULL)
+		return (NULL);
 
-	if (vsl->r_fd > STDIN_FILENO)
-		(void)close(vsl->r_fd);
-	vbit_destroy(vsl->vbm_supress);
-	vbit_destroy(vsl->vbm_select);
-	free(vsl->rbuf);
-	FREE_OBJ(vsl);
-}
+	vsl->vbm_select = vbit_init(256);
+	vsl->vbm_supress = vbit_init(256);
 
-/*--------------------------------------------------------------------*/
+	return (vsl);
+}
 
 void
-VSL_Select(struct VSM_data *vd, enum VSL_tag_e tag)
+VSL_Delete(struct VSL_data *vsl)
 {
-	struct vsl *vsl = vsl_Setup(vd);
-
-	vbit_set(vsl->vbm_select, (int)tag);
-}
 
-/*--------------------------------------------------------------------
- */
-
-static int
-vsl_open(struct VSM_data *vd)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-	int i;
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
 
-	assert(vsl->r_fd < 0);
-	if (vd->head == NULL) {
-		i = VSM_Open(vd);
-		if (i)
-			return (i);
-	}
-	if (!VSM_Get(vd, &vsl->vf, VSL_CLASS, NULL, NULL)) {
-		VSM_Close(vd);
-		return (vsm_diag(vd, "No VSL chunk found "
-		    " (child not started ?)\n"));
-	}
-	vsl->log_start = vsl->vf.b;
-	vsl->log_end = vsl->vf.e;
-	vsl->log_ptr = vsl->log_start + 1;
-	if (!vsl->d_opt) {
-		while (vsl->log_ptr < vsl->log_end &&
-		    *vsl->log_ptr != VSL_ENDMARKER)
-			vsl->log_ptr = VSL_NEXT(vsl->log_ptr);
-	}
-	if (vsl->log_ptr >= vsl->log_end)
-		vsl->log_ptr = vsl->log_start + 1;
-	vsl->last_seq = vsl->log_start[0];
-	return (0);
+	vbit_destroy(vsl->vbm_select);
+	vbit_destroy(vsl->vbm_supress);
+	VSL_ResetError(vsl);
+	FREE_OBJ(vsl);
 }
 
-/*--------------------------------------------------------------------
- */
-
-static void
-vsl_close(struct VSM_data *vd)
+const char *
+VSL_Error(const struct VSL_data *vsl)
 {
-	struct vsl *vsl = vsl_Setup(vd);
 
-	assert(vsl->r_fd < 0);
-	VSM_Close(vd);
-	memset(&vsl->vf, 0, sizeof vsl->vf);
-	vsl->log_start = NULL;
-	vsl->log_end = NULL;
-	vsl->log_ptr = NULL;
-}
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
 
-/*--------------------------------------------------------------------
- * Return the next log record, if there is one
- *
- * Return:
- *	<0: error
- *	0: no record
- *	>0: record available at pp
- */
+	if (vsl->diag == NULL)
+		return (NULL);
+	else
+		return (VSB_data(vsl->diag));
+}
 
-static int
-vsl_nextslt(struct VSM_data *vd, uint32_t **pp)
+void
+VSL_ResetError(struct VSL_data *vsl)
 {
-	struct vsl *vsl = vsl_Setup(vd);
-	unsigned l;
-	uint32_t t;
-	int i;
-
-	*pp = NULL;
-	if (vsl->r_fd != -1) {
-		assert(vsl->rbuflen >= 8);
-		i = read(vsl->r_fd, vsl->rbuf, 8);
-		if (i == 0)
-			return (-2);
-		if (i != 8)
-			return (-1);
-		l = 2 + VSL_WORDS(VSL_LEN(vsl->rbuf));
-		if (vsl->rbuflen < l) {
-			l += 256;
-			vsl->rbuf = realloc(vsl->rbuf, l * 4L);
-			assert(vsl->rbuf != NULL);
-			vsl->rbuflen = l;
-		}
-		i = read(vsl->r_fd, vsl->rbuf + 2, l * 4L - 8L);
-		if (i != (l * 4L - 8L))
-			return (-1);
-		*pp = vsl->rbuf;
-		return (1);
-	}
-
-	if (vsl->log_ptr == NULL && vsl_open(vd))
-		return (0);
-
-	while (1) {
-		assert(vsl->log_ptr >= vsl->log_start + 1);
-		assert(vsl->log_ptr < vsl->log_end);
-		t = *vsl->log_ptr;
-
-		if (t == VSL_WRAPMARKER) {
-			/* Wrap around not possible at front */
-			if (vsl->log_ptr == vsl->log_start + 1)
-				return (-1);
-			vsl->log_ptr = vsl->log_start + 1;
-			continue;
-		}
 
-		if (t == VSL_ENDMARKER) {
-			if (vsl->log_ptr != vsl->log_start + 1 &&
-			    vsl->last_seq != vsl->log_start[0]) {
-				/* ENDMARKER not at front and seq wrapped */
-				vsl->log_ptr = vsl->log_start + 1;
-				continue;
-			}
-			return (0);
-		}
-
-		if (t == 0) {
-			/* Uninitialized VSL */
-			return (0);
-		}
-
-		if (vsl->log_ptr == vsl->log_start + 1)
-			vsl->last_seq = vsl->log_start[0];
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
 
-		*pp = (void*)(uintptr_t)vsl->log_ptr; /* Loose volatile */
-		vsl->log_ptr = VSL_NEXT(vsl->log_ptr);
-		return (1);
-	}
+	if (vsl->diag == NULL)
+		return;
+	VSB_delete(vsl->diag);
+	vsl->diag = NULL;
 }
 
 int
-VSL_NextSLT(struct VSM_data *vd, uint32_t **pp, uint64_t *bits)
+VSL_Match(struct VSL_data *vsl, const struct VSL_cursor *c)
 {
-	struct vsl *vsl = vsl_Setup(vd);
-	uint32_t *p;
-	unsigned char t;
-	int i;
-	struct vsl_re_match *vrm;
-	int j;
-
-	if (bits != NULL)
-		*bits = 0;
-
-	while (1) {
-		i = vsl_nextslt(vd, &p);
-		if (i < 0)
-			return (i);
-		if (i == 0) {
-			if (vsl->d_opt || vsl->r_fd >= 0)
-				return (i);
-			if (!VSM_StillValid(vd, &vsl->vf))
-				vsl_close(vd);
-			return (i);
-		}
+	enum VSL_tag_e tag;
 
-		t = VSL_TAG(p);
-		if (t == SLT__Batch) {
-			continue;
-		} else if (vbit_test(vsl->vbm_select, t)) {
-			/* nothing */
-		} else if (vbit_test(vsl->vbm_supress, t)) {
-			continue;
-		} else if (vsl->b_opt && !VSL_BACKEND(p)) {
-			continue;
-		} else if (vsl->c_opt && !VSL_CLIENT(p)) {
-			continue;
-		} else if (vsl->regincl != NULL) {
-			i = VRE_exec(vsl->regincl, VSL_DATA(p), VSL_LEN(p),
-			    0, 0, NULL, 0, NULL);
-			if (i == VRE_ERROR_NOMATCH)
-				continue;
-		} else if (vsl->regexcl != NULL) {
-			i = VRE_exec(vsl->regexcl, VSL_DATA(p), VSL_LEN(p),
-			    0, 0, NULL, 0, NULL);
-			if (i != VRE_ERROR_NOMATCH)
-				continue;
-		}
-
-		if (vsl->skip) {
-			--vsl->skip;
-			continue;
-		} else if (vsl->keep) {
-			if (--vsl->keep == 0)
-				return (-2);
-		}
-
-		if (bits != NULL) {
-			j = 0;
-			VTAILQ_FOREACH(vrm, &vsl->matchers, next) {
-				if (vrm->tag == t) {
-					i = VRE_exec(vrm->re, VSL_DATA(p),
-					    VSL_LEN(p), 0, 0, NULL, 0, NULL);
-					if (i >= 0)	/* XXX ?? */
-						*bits |= (uintmax_t)1 << j;
-				}
-				j++;
-			}
-		}
-		*pp = p;
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
+	if (c == NULL || c->ptr == NULL)
+		return (0);
+	tag = VSL_TAG(c->ptr);
+	if (tag <= SLT__Bogus || tag >= SLT__Reserved)
+		return (0);
+	if (vbit_test(vsl->vbm_select, tag))
 		return (1);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-VSL_Dispatch(struct VSM_data *vd, VSL_handler_f *func, void *priv)
-{
-	int i;
-	unsigned u, l, s;
-	uint32_t *p;
-	uint64_t bitmap;
+	else if (vbit_test(vsl->vbm_supress, tag))
+		return (0);
 
-	while (1) {
-		i = VSL_NextSLT(vd, &p, &bitmap);
-		if (i <= 0)
-			return (i);
-		u = VSL_ID(p);
-		l = VSL_LEN(p);
-		s = 0;
-		if (VSL_CLIENT(p))
-			s |= VSL_S_CLIENT;
-		if (VSL_BACKEND(p))
-			s |= VSL_S_BACKEND;
-		i = func(priv, (enum VSL_tag_e)VSL_TAG(p),
-		    u, l, s, VSL_DATA(p), bitmap);
-		if (i)
-			return (i);
-	}
+	/* Default show */
+	return (1);
 }
 
-/*--------------------------------------------------------------------*/
-
 int
-VSL_H_Print(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len,
-    unsigned spec, const char *ptr, uint64_t bitmap)
+VSL_Print(struct VSL_data *vsl, const struct VSL_cursor *c, void *fo)
 {
-	FILE *fo = priv;
+	enum VSL_tag_e tag;
+	uint32_t vxid;
+	unsigned len;
+	const char *data;
 	int type;
+	int i;
 
-	(void) bitmap;
-	assert(fo != NULL);
-
-	type = (spec & VSL_S_CLIENT) ? 'c' :
-	    (spec & VSL_S_BACKEND) ? 'b' : '-';
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
+	if (c == NULL || c->ptr == NULL)
+		return (0);
+	if (fo == NULL)
+		fo = stdout;
+	tag = VSL_TAG(c->ptr);
+	vxid = VSL_ID(c->ptr);
+	len = VSL_LEN(c->ptr);
+	type = VSL_CLIENT(c->ptr) ? 'c' : VSL_BACKEND(c->ptr) ? 'b' : '-';
+	data = VSL_CDATA(c->ptr);
 
 	if (tag == SLT_Debug) {
-		fprintf(fo, "%5u %-12s %c \"", fd, VSL_tags[tag], type);
+		i = fprintf(fo, "%10u %-15s %c \"", vxid, VSL_tags[tag], type);
+		if (i < 0)
+			return (-5);
 		while (len-- > 0) {
-			if (*ptr >= ' ' && *ptr <= '~')
-				fprintf(fo, "%c", *ptr);
+			if (*data >= ' ' && *data <= '~')
+				i = fprintf(fo, "%c", *data);
 			else
-				fprintf(fo, "%%%02x", (unsigned char)*ptr);
-			ptr++;
+				i = fprintf(fo, "%%%02x", (unsigned char)*data);
+			if (i < 0)
+				return (-5);
+			data++;
 		}
-		fprintf(fo, "\"\n");
+		i = fprintf(fo, "\"\n");
+		if (i < 0)
+			return (-5);
 		return (0);
 	}
-	fprintf(fo, "%5u %-12s %c %.*s\n",
-	    fd, VSL_tags[tag], type, (int)len, ptr);
-	return (0);
-}
-
-/*--------------------------------------------------------------------*/
 
-int
-VSL_Matched(struct VSM_data *vd, uint64_t bitmap)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-
-	if (vsl->num_matchers > 0) {
-		uint64_t t;
-		t = vsl->num_matchers | (vsl->num_matchers - 1);
-		return (bitmap == t);
-	}
-	return (1);
+	i = fprintf(fo, "%10u %-15s %c %.*s\n",
+	    vxid, VSL_tags[tag], type, (int)len, data);
+	if (i < 0)
+		return (-5);
+	return (0);
 }
diff --git a/lib/libvarnishapi/vsl_api.h b/lib/libvarnishapi/vsl_api.h
index b203ae8..8b70098 100644
--- a/lib/libvarnishapi/vsl_api.h
+++ b/lib/libvarnishapi/vsl_api.h
@@ -1,9 +1,10 @@
 /*-
  * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
+ * Copyright (c) 2006-2013 Varnish Software AS
  * All rights reserved.
  *
  * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,64 +29,38 @@
  *
  */
 
+#include "vdef.h"
 #include "vqueue.h"
+#include "vapi/vsm.h"
 
-#define	SLEEP_USEC			(50*1000)
-#define	TIMEOUT_USEC			(5*1000*1000)
+#define VSL_FILE_HEAD			"VSL"
 
+int vsl_diag(struct VSL_data *vsl, const char *fmt, ...)
+    __printflike(2, 3);
 
-struct vsl_re_match {
-	unsigned			magic;
-#define VSL_RE_MATCH_MAGIC		0x4013151e
-	int				tag;
-	vre_t				*re;
-	VTAILQ_ENTRY(vsl_re_match)	next;
-};
-
-struct vsl {
-	unsigned		magic;
-#define VSL_MAGIC		0x7a31db38
-
-	struct VSM_fantom	vf;
-
-	/* Stuff relating the log records below here */
-
-	volatile uint32_t	*log_start;
-	volatile uint32_t	*log_end;
-	volatile uint32_t	*log_ptr;
+typedef void vslc_delete_f(void *);
+typedef int vslc_next_f(void *);
 
-	volatile uint32_t	last_seq;
-
-	/* for -r option */
-	int			r_fd;
-	unsigned		rbuflen;
-	uint32_t		*rbuf;
-
-	int			b_opt;
-	int			c_opt;
-	int			d_opt;
+struct vslc {
+	struct VSL_cursor		c;
+	unsigned			magic;
+#define VSLC_MAGIC			0x5007C0DE
 
-	unsigned		flags;
-#define F_SEEN_IX		(1 << 0)
+	vslc_delete_f			*delete;
+	vslc_next_f			*next;
+};
 
-	/*
-	 * Bit map of programatically selected tags, that cannot be suppressed.
-	 * This way programs can make sure they will see certain tags, even
-	 * if the user tries to supress them with -x/-X
-	 */
-	struct vbitmap		*vbm_select;	/* index: tag */
+struct VSL_data {
+	unsigned			magic;
+#undef VSL_MAGIC
+#define VSL_MAGIC			0x8E6C92AA
 
-	/* Bit map of tags selected/supressed with -[iIxX] options */
-	struct vbitmap		*vbm_supress;	/* index: tag */
+	struct vsb			*diag;
 
-	int			regflags;
-	vre_t			*regincl;
-	vre_t			*regexcl;
-	int			num_matchers;
-	VTAILQ_HEAD(, vsl_re_match) matchers;
+	unsigned			flags;
+#define F_SEEN_ix			(1 << 0)
 
-	unsigned long		skip;
-	unsigned long		keep;
+	/* Bitmaps of -ix selected tags */
+	struct vbitmap			*vbm_select;
+	struct vbitmap			*vbm_supress;
 };
-
-struct vsl *vsl_Setup(struct VSM_data *vd);
diff --git a/lib/libvarnishapi/vsl_arg.c b/lib/libvarnishapi/vsl_arg.c
index e10567c..72c1f22 100644
--- a/lib/libvarnishapi/vsl_arg.c
+++ b/lib/libvarnishapi/vsl_arg.c
@@ -83,71 +83,20 @@ VSL_Name2Tag(const char *name, int l)
 	return (n);
 }
 
-
-/*--------------------------------------------------------------------*/
-
-static int
-vsl_r_arg(struct VSM_data *vd, const char *opt)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-
-	if (vsl->r_fd > STDIN_FILENO)
-		(void)close(vsl->r_fd);
-	if (!strcmp(opt, "-"))
-		vsl->r_fd = STDIN_FILENO;
-	else
-		vsl->r_fd = open(opt, O_RDONLY);
-	if (vsl->r_fd < 0)
-		return (vsm_diag(vd,
-		    "Could not open %s: %s", opt, strerror(errno)));
-	if (vsl->rbuflen == 0) {
-		vsl->rbuflen = BUFSIZ;
-		vsl->rbuf = malloc(vsl->rbuflen);
-		AN(vsl->rbuf);
-	}
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
 static int
-vsl_IX_arg(struct VSM_data *vd, const char *opt, int arg)
+vsl_ix_arg(struct VSL_data *vsl, int opt, const char *arg)
 {
-	struct vsl *vsl = vsl_Setup(vd);
-	vre_t **rp;
-	const char *error;
-	int erroroffset;
-
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-	if (arg == 'I')
-		rp = &vsl->regincl;
-	else
-		rp = &vsl->regexcl;
-	if (*rp != NULL)
-		return (vsm_diag(vd, "Option %c can only be given once", arg));
-	*rp = VRE_compile(opt, vsl->regflags, &error, &erroroffset);
-	if (*rp == NULL)
-		return (vsm_diag(vd, "Illegal regex: %s\n", error));
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-vsl_ix_arg(struct VSM_data *vd, const char *opt, int arg)
-{
-	struct vsl *vsl = vsl_Setup(vd);
 	int i, l;
 	const char *b, *e;
 
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
 	/* If first option is 'i', set all bits for supression */
-	if (arg == 'i' && !(vsl->flags & F_SEEN_IX))
+	if (opt == 'i' && !(vsl->flags & F_SEEN_ix))
 		for (i = 0; i < 256; i++)
 			vbit_set(vsl->vbm_supress, i);
-	vsl->flags |= F_SEEN_IX;
+	vsl->flags |= F_SEEN_ix;
 
-	for (b = opt; *b; b = e) {
+	for (b = arg; *b; b = e) {
 		while (isspace(*b))
 			b++;
 		e = strchr(b, ',');
@@ -160,123 +109,28 @@ vsl_ix_arg(struct VSM_data *vd, const char *opt, int arg)
 			l--;
 		i = VSL_Name2Tag(b, l);
 		if (i >= 0) {
-			if (arg == 'x')
+			if (opt == 'x')
 				vbit_set(vsl->vbm_supress, i);
 			else
 				vbit_clr(vsl->vbm_supress, i);
 		} else if (i == -2) {
-			return (vsm_diag(vd,
-			    "\"%*.*s\" matches multiple tags\n", l, l, b));
+			return (vsl_diag(vsl,
+			    "-%c: \"%*.*s\" matches multiple tags\n",
+			    (char)opt, l, l, b));
 		} else {
-			return (vsm_diag(vd,
-			    "Could not match \"%*.*s\" to any tag\n", l, l, b));
+			return (vsl_diag(vsl,
+			    "-%c: Could not match \"%*.*s\" to any tag\n",
+			    (char)opt, l, l, b));
 		}
 	}
 	return (1);
 }
 
-/*--------------------------------------------------------------------*/
-
-
-static int
-vsl_m_arg(struct VSM_data *vd, const char *opt)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-	struct vsl_re_match *m;
-	const char *error;
-	char *o, *regex;
-	int erroroffset;
-
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-
-	if (!strchr(opt, ':'))
-		return (vsm_diag(vd,
-		    "No : found in -m option %s\n", opt));
-
-	o = strdup(opt);
-	AN(o);
-	regex = strchr(o, ':');
-	*regex = '\0';
-	regex++;
-
-	ALLOC_OBJ(m, VSL_RE_MATCH_MAGIC);
-	AN(m);
-	m->tag = VSL_Name2Tag(o, -1);
-	if (m->tag < 0) {
-		(void)vsm_diag(vd, "Illegal tag %s specified\n", o);
-		free(o);
-		FREE_OBJ(m);
-		return (-1);
-	}
-	/* Get tag, regex */
-	m->re = VRE_compile(regex, vsl->regflags, &error, &erroroffset);
-	if (m->re == NULL) {
-		(void)vsm_diag(vd, "Illegal regex: %s\n", error);
-		free(o);
-		FREE_OBJ(m);
-		return (-1);
-	}
-	vsl->num_matchers++;
-	VTAILQ_INSERT_TAIL(&vsl->matchers, m, next);
-	free(o);
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-vsl_s_arg(struct VSM_data *vd, const char *opt)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-	char *end;
-
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-	if (*opt == '\0')
-		return (vsm_diag(vd, "number required for -s\n"));
-	vsl->skip = strtoul(opt, &end, 10);
-	if (*end != '\0')
-		return (vsm_diag(vd, "invalid number for -k\n"));
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-vsl_k_arg(struct VSM_data *vd, const char *opt)
-{
-	struct vsl *vsl = vsl_Setup(vd);
-	char *end;
-
-	CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
-	if (*opt == '\0')
-		return (vsm_diag(vd, "number required for -k\n"));
-	vsl->keep = strtoul(opt, &end, 10);
-	if (*end != '\0')
-		return (vsm_diag(vd, "invalid number for -k\n"));
-	return (1);
-}
-
-/*--------------------------------------------------------------------*/
-
 int
-VSL_Arg(struct VSM_data *vd, int arg, const char *opt)
+VSL_Arg(struct VSL_data *vsl, int opt, const char *arg)
 {
-	struct vsl *vsl = vsl_Setup(vd);
-
-	switch (arg) {
-	case 'b': vsl->b_opt = !vsl->b_opt; return (1);
-	case 'c': vsl->c_opt = !vsl->c_opt; return (1);
-	case 'd':
-		vsl->d_opt = !vsl->d_opt;
-		return (1);
-	case 'i': case 'x': return (vsl_ix_arg(vd, opt, arg));
-	case 'k': return (vsl_k_arg(vd, opt));
-	case 'n': return (VSM_n_Arg(vd, opt));
-	case 'r': return (vsl_r_arg(vd, opt));
-	case 's': return (vsl_s_arg(vd, opt));
-	case 'I': case 'X': return (vsl_IX_arg(vd, opt, arg));
-	case 'm': return (vsl_m_arg(vd, opt));
-	case 'C': vsl->regflags = VRE_CASELESS; return (1);
+	switch (opt) {
+	case 'i': case'x': return (vsl_ix_arg(vsl, opt, arg));
 	default:
 		return (0);
 	}
diff --git a/lib/libvarnishapi/vsl_cursor.c b/lib/libvarnishapi/vsl_cursor.c
new file mode 100644
index 0000000..65262d1
--- /dev/null
+++ b/lib/libvarnishapi/vsl_cursor.c
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "vas.h"
+#include "vdef.h"
+#include "miniobj.h"
+#include "vapi/vsm.h"
+#include "vsm_api.h"
+#include "vapi/vsl.h"
+#include "vsl_api.h"
+
+struct vslc_vsm {
+	struct vslc			c;
+	unsigned			magic;
+#define VSLC_VSM_MAGIC			0x4D3903A6
+
+	struct VSM_data			*vsm;
+	struct VSM_fantom		vf;
+
+	volatile const struct VSL_head	*head;
+	volatile const uint32_t		*next;
+	const uint32_t			*end;
+	ssize_t				segsize;
+	unsigned			seq;
+};
+
+static void
+vslc_vsm_delete(void *cursor)
+{
+	struct vslc_vsm *c;
+
+	CAST_OBJ_NOTNULL(c, (void *)cursor, VSLC_VSM_MAGIC);
+	FREE_OBJ(c);
+}
+
+static int
+vslc_vsm_next(void *cursor)
+{
+	struct vslc_vsm *c;
+	int diff;
+	unsigned segment;
+	uint32_t t;
+
+	CAST_OBJ_NOTNULL(c, cursor, VSLC_VSM_MAGIC);
+	CHECK_OBJ_NOTNULL(c->vsm, VSM_MAGIC);
+
+	/* Assert pointers */
+	AN(c->next);
+	assert(c->next >= c->head->log);
+	assert(c->next < c->end);
+
+	/* Check sequence number */
+	diff = c->head->seq - c->seq;
+	if (c->head->seq < c->seq)
+		/* Wrap around skips 0 */
+		diff -= 1;
+	if (diff > 1)
+		return (-3);
+
+	/* Check overrun */
+	segment = (c->next - c->head->log) / c->segsize;
+	if (segment >= VSL_SEGMENTS)
+		segment = VSL_SEGMENTS - 1;
+	diff = (segment - c->head->segment) % VSL_SEGMENTS;
+	if (0 < diff && diff <= 2)
+		return (-3);
+
+	/* Check VSL fantom and abandonment */
+	if (*c->next == VSL_ENDMARKER) {
+		if (!VSM_StillValid(c->vsm, &c->vf) ||
+		    VSM_Abandoned(c->vsm))
+			return (-2);
+	}
+
+	while (1) {
+		assert(c->next >= c->head->log);
+		assert(c->next < c->end);
+		AN(c->head->seq);
+		t = *c->next;
+		AN(t);
+
+		if (t == VSL_WRAPMARKER) {
+			/* Wrap around not possible at front */
+			assert(c->next != c->head->log);
+			c->next = c->head->log;
+			continue;
+		}
+
+		if (t == VSL_ENDMARKER) {
+			if (c->next != c->head->log &&
+			    c->seq != c->head->seq) {
+				/* ENDMARKER not at front and seq wrapped */
+				/* XXX: assert on this? */
+				c->next = c->head->log;
+				continue;
+			}
+			return (0);
+		}
+
+		if (c->next == c->head->log)
+			c->seq = c->head->seq;
+
+		c->c.c.ptr = (void*)(uintptr_t)c->next; /* Loose volatile */
+		c->next = VSL_NEXT(c->next);
+		return (1);
+	}
+}
+
+struct VSL_cursor *
+VSL_CursorVSM(struct VSL_data *vsl, struct VSM_data *vsm, int tail)
+{
+	struct vslc_vsm *c;
+	struct VSM_fantom vf;
+	struct VSL_head *head;
+	unsigned segment;
+
+	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
+	CHECK_OBJ_NOTNULL(vsm, VSM_MAGIC);
+
+	if (!VSM_Get(vsm, &vf, VSL_CLASS, "", "")) {
+		vsl_diag(vsl, "No VSL chunk found (child not started ?)\n");
+		return (NULL);
+	}
+
+	head = vf.b;
+	if (memcmp(head->marker, VSL_HEAD_MARKER, sizeof head->marker)) {
+		vsl_diag(vsl, "Not a VSL chunk\n");
+		return (NULL);
+	}
+	if (head->seq == 0) {
+		vsl_diag(vsl, "VSL chunk not initialized\n");
+		return (NULL);
+	}
+
+	ALLOC_OBJ(c, VSLC_VSM_MAGIC);
+	if (c == NULL) {
+		vsl_diag(vsl, "Out of memory\n");
+		return (NULL);
+	}
+	c->c.magic = VSLC_MAGIC;
+	c->c.delete = vslc_vsm_delete;
+	c->c.next = vslc_vsm_next;
+
+	c->vsm = vsm;
+	c->vf = vf;
+	c->head = head;
+	c->end = vf.e;
+	c->segsize = (c->end - c->head->log) / VSL_SEGMENTS;
+
+	if (tail) {
+		/* Locate tail of log */
+		c->next = c->head->log + c->head->segments[c->head->segment];
+		while (c->next < c->end && *c->next != VSL_ENDMARKER)
+			c->next = VSL_NEXT(c->next);
+	} else {
+		/*
+		 * Starting (VSL_SEGMENTS - 3) behind varnishd. This way
+		 * even if varnishd wraps immediately, we'll still have a
+		 * full segment worth of log before the general constraint
+		 * of at least 2 segments apart will be broken
+		 */
+		segment = (c->head->segment + 3) % VSL_SEGMENTS;
+		if (c->head->segments[segment] < 0)
+			segment = 0;
+		assert(c->head->segments[segment] >= 0);
+		c->next = c->head->log + c->head->segments[segment];
+	}
+	c->seq = c->head->seq;
+
+	return (&c->c.c);
+}
+
+struct vslc_file {
+	struct vslc			c;
+	unsigned			magic;
+#define VSLC_FILE_MAGIC			0x1D65FFEF
+
+	int				error;
+	int				fd;
+	ssize_t				buflen;
+	uint32_t			*buf;
+};
+
+static void
+vslc_file_delete(void *cursor)
+{
+	struct vslc_file *c;
+
+	CAST_OBJ_NOTNULL(c, cursor, VSLC_FILE_MAGIC);
+	if (c->fd > STDIN_FILENO)
+		(void)close(c->fd);
+	if (c->buf != NULL)
+		free(c->buf);
+	FREE_OBJ(c);
+}
+
+static ssize_t
+vslc_file_readn(int fd, void *buf, size_t n)
+{
+	size_t t = 0;
+	ssize_t l;
+
+	while (t < n) {
+		l = read(fd, (char *)buf + t, n - t);
+		if (l <= 0)
+			return (l);
+		t += l;
+	}
+	return (t);
+}
+
+static int
+vslc_file_next(void *cursor)
+{
+	struct vslc_file *c;
+	ssize_t i, l;
+
+	CAST_OBJ_NOTNULL(c, cursor, VSLC_FILE_MAGIC);
+
+	if (c->error)
+		return (c->error);
+
+	do {
+		c->c.c.ptr = NULL;
+		assert(c->buflen >= 2 * 4);
+		i = vslc_file_readn(c->fd, c->buf, 2 * 4);
+		if (i < 0)
+			return (-4);	/* I/O error */
+		if (i == 0)
+			return (-1);	/* EOF */
+		assert(i == 2 * 4);
+		l = (2 + VSL_WORDS(VSL_LEN(c->buf))) * 4;
+		if (c->buflen < l) {
+			c->buf = realloc(c->buf, 2 * l);
+			AN(c->buf);
+			c->buflen = 2 * l;
+		}
+		i = vslc_file_readn(c->fd, c->buf + 2, l - 2 * 4);
+		if (i < 0)
+			return (-4);	/* I/O error */
+		if (i == 0)
+			return (-1);	/* EOF */
+		assert(i == l - 2 * 4);
+		c->c.c.ptr = c->buf;
+	} while (c->c.c.ptr != NULL && VSL_TAG(c->c.c.ptr) == SLT__Batch);
+	return (1);
+}
+
+struct VSL_cursor *
+VSL_CursorFile(struct VSL_data *vsl, const char *name)
+{
+	struct vslc_file *c;
+	int fd;
+	char buf[4];
+	ssize_t i;
+
+	if (!strcmp(name, "-")) {
+		fd = open(name, O_RDONLY);
+		if (fd < 0) {
+			vsl_diag(vsl, "Could not open %s: %s\n", name,
+			    strerror(errno));
+			return (NULL);
+		}
+	} else
+		fd = STDIN_FILENO;
+
+	i = vslc_file_readn(fd, buf, sizeof buf);
+	if (i <= 0) {
+		if (fd > STDIN_FILENO)
+			(void)close(fd);
+		vsl_diag(vsl, "VSL file read error: %s\n",
+		    i < 0 ? strerror(errno) : "EOF");
+		return (NULL);
+	}
+	assert(i == sizeof buf);
+	if (memcmp(buf, VSL_FILE_HEAD, sizeof buf)) {
+		if (fd > STDIN_FILENO)
+			(void)close(fd);
+		vsl_diag(vsl, "Not a VSL file: %s\n", name);
+		return (NULL);
+	}
+
+	ALLOC_OBJ(c, VSLC_FILE_MAGIC);
+	if (c == NULL) {
+		if (fd > STDIN_FILENO)
+			(void)close(fd);
+		vsl_diag(vsl, "Out of memory\n");
+		return (NULL);
+	}
+	c->c.magic = VSLC_MAGIC;
+	c->c.delete = vslc_file_delete;
+	c->c.next = vslc_file_next;
+
+	c->fd = fd;
+	c->buflen = BUFSIZ;
+	c->buf = malloc(c->buflen);
+	AN(c->buf);
+
+	return (&c->c.c);
+}
+
+void
+VSL_DeleteCursor(struct VSL_cursor *cursor)
+{
+	struct vslc *c;
+
+	CAST_OBJ_NOTNULL(c, (void *)cursor, VSLC_MAGIC);
+	if (c->delete == NULL)
+		return;
+	(c->delete)(c);
+}
+
+int
+VSL_Next(struct VSL_cursor *cursor)
+{
+	struct vslc *c;
+
+	CAST_OBJ_NOTNULL(c, (void *)cursor, VSLC_MAGIC);
+	AN(c->next);
+	return ((c->next)(c));
+}
diff --git a/lib/libvarnishapi/vsm.c b/lib/libvarnishapi/vsm.c
index a957293..b40e3d4 100644
--- a/lib/libvarnishapi/vsm.c
+++ b/lib/libvarnishapi/vsm.c
@@ -163,8 +163,7 @@ VSM_Delete(struct VSM_data *vd)
 	free(vd->fname);
 	if (vd->vsc != NULL)
 		VSC_Delete(vd);
-	if (vd->vsl != NULL)
-		VSL_Delete(vd);
+	VSM_ResetError(vd);
 	FREE_OBJ(vd);
 }
 
diff --git a/lib/libvarnishapi/vsm_api.h b/lib/libvarnishapi/vsm_api.h
index 2942494..04ebd7f 100644
--- a/lib/libvarnishapi/vsm_api.h
+++ b/lib/libvarnishapi/vsm_api.h
@@ -57,4 +57,3 @@ struct VSM_data {
 int vsm_diag(struct VSM_data *vd, const char *fmt, ...)
     __printflike(2, 3);
 void VSC_Delete(struct VSM_data *vd);
-void VSL_Delete(struct VSM_data *vd);



More information about the varnish-commit mailing list