summaryrefslogtreecommitdiffstats
path: root/lib/session.c
diff options
context:
space:
mode:
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);