# as -version-info 2:0:0. This release has a new, but backwards incompatible
# interface.
-LIBVERSION = 2:1:0
+# curr:rev:age
+LIBVERSION = 3:0:1
AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include \
-I/usr/local/include
typedef int (*ipset_outfn)(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
+extern int ipset_session_outfn(struct ipset_session *session,
+ ipset_outfn outfn);
extern struct ipset_session *ipset_session_init(ipset_outfn outfn);
extern int ipset_session_fini(struct ipset_session *session);
include $(top_srcdir)/lib/Make_extra.am
-libipset_la_LDFLAGS = -Wl,--version-script=$(top_srcdir)/lib/libipset.map -version-info $(LIBVERSION)
+libipset_la_LDFLAGS = -Wl,--version-script=$(top_srcdir)/lib/libipset.map -version-number $(LIBVERSION)
libipset_la_LIBADD = ${libmnl_LIBS} $(IPSET_SETTYPE_STATIC_OBJECTS)
libipset_la_SOURCES = \
data.c \
ipset_parse_timeout;
ipset_data_test_ignored;
} LIBIPSET_1.0;
+
+LIBIPSET_3.0 {
+global:
+ ipset_session_outfn;
+} LIBIPSET_2.0;
return ret;
}
+/**
+ * ipset_session_outfn - set session output printing function
+ *
+ * Set the session printing function.
+ *
+ */
+int
+ipset_session_outfn(struct ipset_session *session, ipset_outfn outfn)
+{
+ session->outfn = outfn ? outfn : printf;
+ return 0;
+}
+
/**
* ipset_session_init - initialize an ipset session
*
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.TH "IPSET" "8" "Oct 15, 2010" "Jozsef Kadlecsik" ""
+.TH "IPSET" "8" "May 23, 2012" "Jozsef Kadlecsik" ""
.SH "NAME"
ipset \(em administration tool for IP sets
.SH "SYNOPSIS"
.PP
COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
.PP
-\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
+\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR | \fB\-file\fR \fIfilename\fR }
.PP
\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
.PP
\fB\-name\fR
is specified, just the names of the existing sets are listed. If the option
\fB\-terse\fR
-is specified, just the set names and headers are listed.
+is specified, just the set names and headers are listed. The output is printed
+to stdout, the option
+\fB\-file\fR
+can be used to specify a filename instead of stdout.
.TP
\fBsave\fP [ \fISETNAME\fP ]
Save the given set, or all sets if none is given
to stdout in a format that
\fBrestore\fP
-can read.
+can read. The option
+\fB\-file\fR
+can be used to specify a filename instead of stdout.
.TP
\fBrestore\fP
Restore a saved session generated by
\fBsave\fP.
-The saved session can be fed from stdin.
+The saved session can be fed from stdin or the option
+\fB\-file\fR
+can be used to specify a filename instead of stdin.
.TP
\fBflush\fP [ \fISETNAME\fP ]
Flush all entries from the specified set or flush
.TP
\fB\-t\fP, \fB\-terse\fP
List the set names and headers, i.e. suppress listing of set members.
-
+.TP
+\fB\-f\fP, \fB\-file\fP \fIfilename\fR
+Specidy a filename to print into instead of stdout
+(\fBlist\fR
+or
+\fBsave\fR
+commands) or read from instead of stdin
+(\fBrestore\fR
+command).
.SH "SET TYPES"
A set type comprises of the storage method by which the data is stored and
the data type(s) which are stored in the set. Therefore the
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <assert.h> /* assert */
#include <ctype.h> /* isspace */
+#include <errno.h> /* errno */
#include <stdarg.h> /* va_* */
#include <stdbool.h> /* bool */
#include <stdio.h> /* fprintf, fgets */
static char cmdline[1024];
static char *newargv[255];
static int newargc;
+static FILE *fd = NULL;
+static const char *filename = NULL;
enum exittype {
NO_PROBLEM = 0,
ipset_session_fini(session);
D("status: %u", status);
+ if (fd)
+ fclose(fd);
exit(status > VERSION_PROBLEM ? OTHER_PROBLEM : status);
/* Unreached */
return -1;
if (!interactive) {
ipset_session_fini(session);
+ if (fd)
+ fclose(fd);
exit(OTHER_PROBLEM);
}
}
}
+int
+ipset_parse_file(struct ipset_session *session UNUSED,
+ int opt UNUSED, const char *str)
+{
+ if (filename != NULL)
+ return exit_error(PARAMETER_PROBLEM,
+ "-file option can be specified once");
+ filename = str;
+
+ return 0;
+}
+
+int __attribute__ ((format (printf, 1, 2)))
+ipset_print_file(const char *fmt, ...)
+{
+ int len;
+ va_list args;
+
+ assert(fd != NULL);
+ va_start(args, fmt);
+ len = vfprintf(fd, fmt, args);
+ va_end(args);
+
+ return len;
+}
+
/* Build faked argv from parsed line */
static void
build_argv(char *buffer)
{
int ret = 0;
char *c;
+ FILE *fread = stdin;
/* Initialize newargv/newargc */
newargc = 0;
newargv[newargc++] = argv0;
+ if (filename) {
+ fd = fopen(filename, "r");
+ if (!fd) {
+ return exit_error(OTHER_PROBLEM,
+ "Cannot open %s for reading: %s",
+ filename, strerror(errno));
+ }
+ fread = fd;
+ }
- while (fgets(cmdline, sizeof(cmdline), stdin)) {
+ while (fgets(cmdline, sizeof(cmdline), fread)) {
restore_line++;
c = cmdline;
while (isspace(c[0]))
check_allowed(type, cmd);
break;
- case IPSET_CMD_DESTROY:
- case IPSET_CMD_FLUSH:
case IPSET_CMD_LIST:
case IPSET_CMD_SAVE:
+ if (filename != NULL) {
+ fd = fopen(filename, "w");
+ if (!fd)
+ return exit_error(OTHER_PROBLEM,
+ "Cannot open %s for writing: "
+ "%s", filename,
+ strerror(errno));
+ ipset_session_outfn(session, ipset_print_file);
+ }
+ case IPSET_CMD_DESTROY:
+ case IPSET_CMD_FLUSH:
/* Args: [setname] */
if (arg0) {
ret = ipset_parse_setname(session,
ret = parse_commandline(argc, argv);
ipset_session_fini(session);
+ if (fd)
+ fclose(fd);
return ret;
}
(name[1] != NULL && tolower(arg[0]) == name[1][0]);
}
+/* Used up so far
+ *
+ * -A add
+ * -D del
+ * -E rename
+ * -f -file
+ * -F flush
+ * -h help
+ * -H help
+ * -L list
+ * -n -name
+ * -N create
+ * -o -output
+ * -r -resolve
+ * -R restore
+ * -s -sorted
+ * -S save
+ * -t -terse
+ * -T test
+ * -q -quiet
+ * -X destroy
+ * -v version
+ * -V version
+ * -W swap
+ * -! -exist
+ */
+
+int
+ipset_parse_file(struct ipset_session *session,
+ int opt, const char *str);
+
const struct ipset_envopts ipset_envopts[] = {
{ .name = { "-o", "-output" },
.has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX,
" When listing, list setnames and set headers\n"
" from kernel only.",
},
+ { .name = { "-f", "-file" },
+ .parse = ipset_parse_file,
+ .has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX,
+ .help = "\n"
+ " Read from the given file instead of standard\n"
+ " input (restore) or write to given file instead\n"
+ " of standard output (list/save).",
+ },
{ },
};