]> granicus.if.org Git - ipset/commitdiff
Allow saving to/restoring from a file without shell redirection
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Wed, 23 May 2012 21:27:42 +0000 (23:27 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Wed, 23 May 2012 21:27:42 +0000 (23:27 +0200)
Mathieu Bridon suggested that in some environments where there is no
access to a full shell with input/output redirection, it'd be useful
to read from/write to directly a file (bugzilla #788).

The patch adds the new "-file" option to specify a filename to print
into when listing/saving sets or read from when restoring sets.

Make_global.am
include/libipset/session.h
lib/Makefile.am
lib/libipset.map
lib/session.c
src/ipset.8
src/ipset.c
src/ui.c

index 24a1a34e53207725eeba55155696e9731a04d8cb..4a8f61a9c31cc0a9c5367f8d3ed66df2a336cd81 100644 (file)
@@ -68,7 +68,8 @@
 # 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
index 467bb2f208616f2b516a99ca90b75854f34db8d5..988233e9ce9d4daa743271d688a87a1f3f3ec0c5 100644 (file)
@@ -97,6 +97,8 @@ extern int ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd,
 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);
 
index fd853dd257e0eecd80f8986589494bc704a705f1..392b5f9eb47876740e84ac7f68ca35c23c4e5b72 100644 (file)
@@ -19,7 +19,7 @@ lib_LTLIBRARIES = libipset.la
 
 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 \
index fd6b8c090cdcf1fb40747c17e55d6b9fd9fe566d..74370b2ef72c26217fa2739db96549b935e76351 100644 (file)
@@ -117,3 +117,8 @@ global:
   ipset_parse_timeout;
   ipset_data_test_ignored;
 } LIBIPSET_1.0;
+
+LIBIPSET_3.0 {
+global:
+  ipset_session_outfn;
+} LIBIPSET_2.0;
index 6700ea18a1c08b01d37a2ed87c6751f510c5e01c..3803bfa07ca0c86d153a2ae628ef812a2e09cc29 100644 (file)
@@ -1940,6 +1940,19 @@ cleanup:
        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
  *
index a2ee39ff4f5e4348cf2c40d888b5903104a9f174..d140f3dcd314aa82e73b9e0004c11996fde914dc 100644 (file)
@@ -13,7 +13,7 @@
 .\" 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"
@@ -21,7 +21,7 @@ ipset \(em administration tool for IP sets
 .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 
@@ -126,18 +126,25 @@ If the option
 \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
@@ -201,7 +208,15 @@ List just the names of the existing sets, i.e. suppress listing of set headers a
 .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
index 4a20ca16280ced7fedcd8bc6583633368d87f3d8..8e5411ff9aa6e00b3a16703bbdc6357b88b65ada 100644 (file)
@@ -6,7 +6,9 @@
  * 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 */
@@ -32,6 +34,8 @@ static bool interactive;
 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,
@@ -74,6 +78,8 @@ exit_error(int status, const char *msg, ...)
                ipset_session_fini(session);
 
        D("status: %u", status);
+       if (fd)
+               fclose(fd);
        exit(status > VERSION_PROBLEM ? OTHER_PROBLEM : status);
        /* Unreached */
        return -1;
@@ -92,6 +98,8 @@ handle_error(void)
 
        if (!interactive) {
                ipset_session_fini(session);
+               if (fd)
+                       fclose(fd);
                exit(OTHER_PROBLEM);
        }
 
@@ -120,6 +128,32 @@ help(void)
        }
 }
 
+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)
@@ -156,12 +190,22 @@ restore(char *argv0)
 {
        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]))
@@ -624,10 +668,19 @@ parse_commandline(int argc, char *argv[])
                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,
@@ -721,6 +774,8 @@ main(int argc, char *argv[])
        ret = parse_commandline(argc, argv);
 
        ipset_session_fini(session);
+       if (fd)
+               fclose(fd);
 
        return ret;
 }
index 7e40bde69e13769c616a2934f02734c5774238fd..0ebacbb7da19b3a5ba0f611aa674b2eb4f0f9f7f 100644 (file)
--- a/src/ui.c
+++ b/src/ui.c
@@ -154,6 +154,37 @@ ipset_match_cmd(const char *arg, const char * const name[])
                       (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,
@@ -202,6 +233,14 @@ const struct ipset_envopts ipset_envopts[] = {
                  "        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).",
+       },
        { },
 };