From 1111253c178870e504bede58d352d530448de97c Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Sun, 19 Jun 2011 18:59:23 +0000 Subject: add logic to support the --concurrent option: use a file lock to support concurrent scripts running ebtables --- userspace/ebtables2/libebtc.c | 67 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/userspace/ebtables2/libebtc.c b/userspace/ebtables2/libebtc.c index f76a04c..4a9a79d 100644 --- a/userspace/ebtables2/libebtc.c +++ b/userspace/ebtables2/libebtc.c @@ -32,6 +32,7 @@ #include #include #include +#include static void decrease_chain_jumps(struct ebt_u_replace *replace); static int iterate_entries(struct ebt_u_replace *replace, int type); @@ -130,16 +131,82 @@ void ebt_list_extensions() } } +#define LOCKDIR "/var/lib/ebtables" +#define LOCKFILE LOCKDIR"/lock" +static int lockfd = -1, locked; +int use_lockfd; +/* Returns 0 on success, -1 when the file is locked by another process + * or -2 on any other error. */ +static int lock_file() +{ + int try = 0; + int ret = 0; + sigset_t sigset; + +tryagain: + /* the SIGINT handler will call unlock_file. To make sure the state + * of the variable locked is correct, we need to temporarily mask the + * SIGINT interrupt. */ + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_BLOCK, &sigset, NULL); + lockfd = open(LOCKFILE, O_CREAT | O_EXCL | O_WRONLY, 00600); + if (lockfd < 0) { + if (errno == EEXIST) + ret = -1; + else if (try == 1) + ret = -2; + else { + if (mkdir(LOCKDIR, 00700)) + ret = -2; + else { + try = 1; + goto tryagain; + } + } + } else { + close(lockfd); + locked = 1; + } + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + return ret; +} + +void unlock_file() +{ + if (locked) { + remove(LOCKFILE); + locked = 0; + } +} + +void __attribute__ ((destructor)) onexit() +{ + if (use_lockfd) + unlock_file(); +} /* Get the table from the kernel or from a binary file * init: 1 = ask the kernel for the initial contents of a table, i.e. the * way it looks when the table is insmod'ed * 0 = get the current data in the table */ int ebt_get_kernel_table(struct ebt_u_replace *replace, int init) { + int ret; + if (!ebt_find_table(replace->name)) { ebt_print_error("Bad table name '%s'", replace->name); return -1; } + while (use_lockfd && (ret = lock_file())) { + if (ret == -2) { + /* if we get an error we can't handle, we exit. This + * doesn't break backwards compatibility since using + * this file locking is disabled by default. */ + ebt_print_error2("Unable to create lock file "LOCKFILE); + } + fprintf(stderr, "Trying to obtain lock %s\n", LOCKFILE); + sleep(1); + } /* Get the kernel's information */ if (ebt_get_table(replace, init)) { if (ebt_errormsg[0] != '\0') -- cgit v1.2.3