summaryrefslogtreecommitdiffstats
path: root/lib/session.c
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2018-10-18 17:27:49 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2018-10-18 17:27:49 +0200
commit55fdd96e331e920ee62bd816a572ac24f6dcd1ae (patch)
tree74e53ff7174e08b035b85f95977ff6919e315b01 /lib/session.c
parenta27741493db0d824a51775e387cf3972a471f64e (diff)
Library reworked to support embedding ipset completely
The ipset library is rewritten/extended to support embedding ipset, so that sets can fully be managed without calling the ipset binary. The ipset binary relies completely on the new library. The libipset.3 manpage was written about the library functions and usage. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Diffstat (limited to 'lib/session.c')
-rw-r--r--lib/session.c316
1 files changed, 279 insertions, 37 deletions
diff --git a/lib/session.c b/lib/session.c
index 16b5549..e782573 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -10,6 +10,7 @@
#include <setjmp.h> /* setjmp, longjmp */
#include <stdio.h> /* snprintf */
#include <stdarg.h> /* va_* */
+#include <stdbool.h> /* bool */
#include <stdlib.h> /* free */
#include <string.h> /* str* */
#include <unistd.h> /* getpagesize */
@@ -25,7 +26,7 @@
#include <libipset/transport.h> /* transport */
#include <libipset/mnl.h> /* default backend */
#include <libipset/utils.h> /* STREQ */
-#include <libipset/ui.h> /* IPSET_ENV_* */
+#include <libipset/ipset.h> /* IPSET_ENV_* */
#include <libipset/session.h> /* prototypes */
#define IPSET_NEST_MAX 4
@@ -47,7 +48,11 @@ struct ipset_session {
/* Output buffer */
char outbuf[IPSET_OUTBUFLEN]; /* Output buffer */
enum ipset_output_mode mode; /* Output mode */
- ipset_outfn outfn; /* Output function */
+ ipset_print_outfn print_outfn; /* Output function to file */
+ void *p; /* Private data for print_outfn */
+ /* Session IO */
+ bool normal_io, full_io; /* Default/normal/full IO */
+ FILE *istream, *ostream; /* Session input/output stream */
/* Error/warning reporting */
char report[IPSET_ERRORBUFLEN]; /* Error/report buffer */
char *errmsg;
@@ -115,41 +120,24 @@ ipset_session_lineno(struct ipset_session *session, uint32_t lineno)
session->lineno = lineno;
}
-/*
- * Environment options
- */
-
/**
- * ipset_envopt_parse - parse/set environment option
+ * ipset_session_printf_private - returns the session private pointer
* @session: session structure
- * @opt: environment option
- * @arg: option argument (unused)
- *
- * Parse and set an environment option.
*
- * Returns 0 on success or a negative error code.
+ * Returns the private pointer in the session structure,
+ * for private/custom print fuctions.
*/
-int
-ipset_envopt_parse(struct ipset_session *session, int opt,
- const char *arg UNUSED)
+void *
+ipset_session_printf_private(struct ipset_session *session)
{
assert(session);
-
- switch (opt) {
- case IPSET_ENV_SORTED:
- case IPSET_ENV_QUIET:
- case IPSET_ENV_RESOLVE:
- case IPSET_ENV_EXIST:
- case IPSET_ENV_LIST_SETNAME:
- case IPSET_ENV_LIST_HEADER:
- session->envopts |= opt;
- return 0;
- default:
- break;
- }
- return -1;
+ return session->p;
}
+/*
+ * Environment options
+ */
+
/**
* ipset_envopt_test - test environment option
* @session: session structure
@@ -167,6 +155,34 @@ ipset_envopt_test(struct ipset_session *session, enum ipset_envopt opt)
}
/**
+ * ipset_envopt_set - set environment option
+ * @session: session structure
+ * @opt: environment option
+ *
+ * Set an environment option of the session.
+ */
+void
+ipset_envopt_set(struct ipset_session *session, enum ipset_envopt opt)
+{
+ assert(session);
+ session->envopts |= opt;
+}
+
+/**
+ * ipset_envopt_unset - unset environment option
+ * @session: session structure
+ * @opt: environment option
+ *
+ * Unset an environment option of the session.
+ */
+void
+ipset_envopt_unset(struct ipset_session *session, enum ipset_envopt opt)
+{
+ assert(session);
+ session->envopts &= ~opt;
+}
+
+/**
* ipset_session_output - set the session output mode
* @session: session structure
* @mode: output mode
@@ -722,7 +738,8 @@ static const char cmd2name[][9] = {
static inline int
call_outfn(struct ipset_session *session)
{
- int ret = session->outfn("%s", session->outbuf);
+ int ret = session->print_outfn(session, session->p,
+ "%s", session->outbuf);
session->outbuf[0] = '\0';
@@ -2034,29 +2051,57 @@ cleanup:
return ret;
}
+static
+int __attribute__ ((format (printf, 3, 4)))
+default_print_outfn(struct ipset_session *session, void *p UNUSED,
+ const char *fmt, ...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = vfprintf(session->ostream, fmt, args);
+ va_end(args);
+
+ return len;
+}
+
/**
- * ipset_session_outfn - set session output printing function
+ * ipset_session_print_outfn - set session output printing function
+ * @session: session structure
+ * @outfn: output printing function
+ * @p: pointer to private area
*
- * Set the session printing function.
+ * Set the session output printing function. If the @outfn is NULL,
+ * then the default output function is configured. You can set
+ * the @p pointer to a private area: the output printing function
+ * is called with @p in one of its arguments.
*
+ * Returns 0 on success or a negative error code.
*/
int
-ipset_session_outfn(struct ipset_session *session, ipset_outfn outfn)
+ipset_session_print_outfn(struct ipset_session *session,
+ ipset_print_outfn outfn,
+ void *p)
{
- session->outfn = outfn ? outfn : printf;
+ session->print_outfn = outfn ? outfn : default_print_outfn;
+ session->p = p;
return 0;
}
/**
* ipset_session_init - initialize an ipset session
+ * @outfn: output printing function
+ * @p: pointer to private area
*
* Initialize an ipset session by allocating a session structure
- * and filling out with the initialization data.
+ * and filling out with the initialization data. The function
+ * calls ipset_session_print_outfn() to set @print_outfn, @p.
*
* Returns the created session sctructure on success or NULL.
*/
struct ipset_session *
-ipset_session_init(ipset_outfn outfn)
+ipset_session_init(ipset_print_outfn print_outfn, void *p)
{
struct ipset_session *session;
size_t bufsize = getpagesize();
@@ -2067,12 +2112,14 @@ ipset_session_init(ipset_outfn outfn)
return NULL;
session->bufsize = bufsize;
session->buffer = session + 1;
+ session->istream = stdin;
+ session->ostream = stdout;
/* The single transport method yet */
session->transport = &ipset_mnl_transport;
/* Output function */
- session->outfn = outfn;
+ ipset_session_print_outfn(session, print_outfn, p);
/* Initialize data structures */
session->data = ipset_data_init();
@@ -2088,6 +2135,197 @@ free_session:
}
/**
+ * ipset_session_io_full - set full IO for the session
+ * @session: session structure
+ * @filename: filename
+ * @what: operate on input/output
+ *
+ * The normal "-file" CLI interface does not provide an interface
+ * to set both the input (restore) and output (list/save) for
+ * a session. This function makes it possible to configure those.
+ *
+ * When a filename for input is passed, then the file will be opened
+ * for reading.
+ * When a filename for output is passed, then the file will be opened
+ * for writing.
+ * Previously opened files are closed.
+ * If NULL is passed as filename, stdin/stdout is set.
+ * Input/output files can be set separatedly.
+ * The function returns error if the file cannot be opened or
+ * normal IO mode is already set.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_session_io_full(struct ipset_session *session, const char *filename,
+ enum ipset_io_type what)
+{
+ FILE *f;
+
+ assert(session);
+
+ if (session->normal_io)
+ return ipset_err(session,
+ "Normal IO is in use, full IO cannot be selected");
+
+ switch (what) {
+ case IPSET_IO_INPUT:
+ if (session->istream != stdin)
+ fclose(session->istream);
+ if (!filename) {
+ session->istream = stdin;
+ } else {
+ f = fopen(filename, "r");
+ if (!f)
+ return ipset_err(session,
+ "Cannot open %s for reading: %s",
+ filename, strerror(errno));
+ session->istream = f;
+ }
+ break;
+ case IPSET_IO_OUTPUT:
+ if (session->ostream != stdout)
+ fclose(session->ostream);
+ if (!filename) {
+ session->ostream = stdout;
+ } else {
+ f = fopen(filename, "w");
+ if (!f)
+ return ipset_err(session,
+ "Cannot open %s for writing: %s",
+ filename, strerror(errno));
+ session->ostream = f;
+ }
+ break;
+ default:
+ return ipset_err(session,
+ "Library error, invalid ipset_io_type");
+ }
+ session->full_io = !(session->istream == stdin &&
+ session->ostream == stdout);
+ return 0;
+}
+
+/**
+ * ipset_session_io_normal - set normal IO for the session
+ * @session: session structure
+ * @filename: filename
+ * @what: operate on input/output
+ *
+ * The normal "-file" CLI interface to set either the input (restore)
+ * or output (list/save) for a session. This function does not make
+ * possible to set both independently.
+ *
+ * When a filename for input is passed, then the file will be opened
+ * for reading.
+ * When a filename for output is passed, then the file will be opened
+ * for writing.
+ * Previously opened files are closed.
+ * If NULL is passed as filename, stdin/stdout is set.
+ * Input/output files cannot be set separatedly.
+ * The function returns error if the file cannot be opened or
+ * full IO mode is already set.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_session_io_normal(struct ipset_session *session, const char *filename,
+ enum ipset_io_type what)
+{
+ FILE *f;
+
+ assert(session);
+ assert(filename);
+
+ if (session->full_io)
+ return ipset_err(session,
+ "Full IO is in use, normal IO cannot be selected");
+ if (session->istream != stdin) {
+ fclose(session->istream);
+ session->istream = stdin;
+ }
+ if (session->ostream != stdout) {
+ fclose(session->ostream);
+ session->ostream = stdout;
+ }
+ switch (what) {
+ case IPSET_IO_INPUT:
+ f = fopen(filename, "r");
+ if (!f)
+ return ipset_err(session,
+ "Cannot open %s for reading: %s",
+ filename, strerror(errno));
+ session->istream = f;
+ break;
+ case IPSET_IO_OUTPUT:
+ f = fopen(filename, "w");
+ if (!f)
+ return ipset_err(session,
+ "Cannot open %s for writing: %s",
+ filename, strerror(errno));
+ session->ostream = f;
+ break;
+ default:
+ return ipset_err(session,
+ "Library error, invalid ipset_io_type");
+ }
+ session->normal_io = !(session->istream == stdin &&
+ session->ostream == stdout);
+ return 0;
+}
+
+/**
+ * ipset_session_io_stream - returns the input or output stream
+ * @what: operate on input/output
+ *
+ * Returns the input or output stream of the session.
+ */
+FILE *
+ipset_session_io_stream(struct ipset_session *session,
+ enum ipset_io_type what)
+{
+ switch (what) {
+ case IPSET_IO_INPUT:
+ return session->istream;
+ case IPSET_IO_OUTPUT:
+ return session->ostream;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * ipset_session_io_close - closes the input or output stream
+ * @what: operate on input/output
+ *
+ * Closes the input or output stream of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_session_io_close(struct ipset_session *session,
+ enum ipset_io_type what)
+{
+ switch (what) {
+ case IPSET_IO_INPUT:
+ if (session->istream != stdin) {
+ fclose(session->istream);
+ session->istream = stdin;
+ }
+ break;
+ case IPSET_IO_OUTPUT:
+ if (session->ostream != stdout) {
+ fclose(session->ostream);
+ session->ostream = stdout;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
* ipset_session_fini - destroy an ipset session
* @session: session structure
*
@@ -2104,6 +2342,10 @@ ipset_session_fini(struct ipset_session *session)
session->transport->fini(session->handle);
if (session->data)
ipset_data_fini(session->data);
+ if (session->istream != stdin)
+ fclose(session->istream);
+ if (session->ostream != stdout)
+ fclose(session->ostream);
ipset_cache_fini();
free(session);