more cleanup
diff --git a/libebtc.c b/libebtc.c
index 964fa8e..6760dbc 100644
--- a/libebtc.c
+++ b/libebtc.c
@@ -23,12 +23,10 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <getopt.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <netinet/ether.h>
 #include "include/ebtables_u.h"
 #include "include/ethernetdb.h"
 #include <unistd.h>
@@ -140,7 +138,7 @@
 int ebt_get_kernel_table(struct ebt_u_replace *replace, int init)
 {
 	if (!ebt_find_table(replace->name)) {
-		ebt_print_error("Bad table name");
+		ebt_print_error("Bad table name '%s'", replace->name);
 		return -1;
 	}
 	/* Get the kernel's information */
@@ -149,7 +147,7 @@
 			return -1;
 		ebtables_insmod("ebtables");
 		if (ebt_get_table(replace, init)) {
-			ebt_print_error("The kernel doesn't support the ebtables %s table", replace->name);
+			ebt_print_error("The kernel doesn't support the ebtables '%s' table", replace->name);
 			return -1;
 		}
 	}
@@ -212,10 +210,7 @@
 			else
 				break;
 		}
-		entries->nentries = 0;
-		entries->counter_offset = 0;
 		u_e1 = entries->entries;
-		entries->entries = NULL;
 		while (u_e1) {
 			ebt_free_u_entry(u_e1);
 			u_e2 = u_e1->next;
@@ -223,6 +218,11 @@
 			u_e1 = u_e2;
 		}
 	}
+	for (i = 0; i < NF_BR_NUMHOOKS; i++)
+		if (replace->hook_entry[i]) {
+			free(replace->hook_entry[i]);
+			replace->hook_entry[i] = NULL;
+		}
 	udc1 = replace->udc;
 	while (udc1) {
 		free(udc1->udc);
@@ -314,8 +314,6 @@
 	free(e->t);
 }
 
-/* Blatently stolen (again) from iptables.c userspace program
- * find out where the modprobe utility is located */
 static char *get_modprobe(void)
 {
 	int procfile;
@@ -327,12 +325,9 @@
 
 	ret = malloc(1024);
 	if (ret) {
-		switch (read(procfile, ret, 1024)) {
-		case -1: goto fail;
-		case 1024: goto fail; /* Partial read.  Wierd */
-		}
-		if (ret[strlen(ret)-1] == '\n')
-			ret[strlen(ret)-1] = 0;
+		if (read(procfile, ret, 1024) == -1)
+			goto fail;
+		ret[1023] = '\0';
 		close(procfile);
 		return ret;
 	}
@@ -343,7 +338,7 @@
 }
 
 char *ebt_modprobe;
-/* Try to load the kernel module */
+/* Try to load the kernel module, analogous to ip_tables.c */
 int ebtables_insmod(const char *modname)
 {
 	char *buf = NULL;
@@ -380,8 +375,7 @@
 /* Gives back a pointer to the chain base, based on nr.
  * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain.
  * Returns NULL on failure. */
-struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
-				       int nr)
+struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, int nr)
 {
 	if (nr == -1)
 		return NULL;
@@ -418,7 +412,7 @@
 	struct ebt_u_chain_list *cl = replace->udc;
 
 	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-		if (!(replace->valid_hooks & (1 << i)))
+		if (!replace->hook_entry[i])
 			continue;
 		if (!strcmp(arg, replace->hook_entry[i]->name))
 			return replace->hook_entry[i];
@@ -439,7 +433,7 @@
 	struct ebt_u_chain_list *cl = replace->udc;
 
 	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-		if (!(replace->valid_hooks & (1 << i)))
+		if (!replace->hook_entry[i])
 			continue;
 		if (!strcmp(arg, replace->hook_entry[i]->name))
 			return i;
@@ -473,7 +467,7 @@
 }
 
 /* Flush one chain or the complete table
- * If selected_chain == -1: flush the complete table */
+ * If selected_chain == -1 then flush the complete table */
 void ebt_flush_chains(struct ebt_u_replace *replace)
 {
 	int i, j, numdel;
@@ -690,8 +684,8 @@
  * This function expects the ebt_{match,watcher,target} members of new_entry
  * to contain pointers to ebt_u_{match,watcher,target} and updates these
  * pointers so that they point to ebt_{match,watcher,target}, before adding
- * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a
- * successful call to ebt_add_rule() */
+ * the rule to the chain. Don't free() the ebt_{match,watcher,target} and
+ * don't reuse the new_entry after a successful call to ebt_add_rule() */
 void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
 		  int rule_nr)
 {
@@ -717,7 +711,7 @@
 
 	/* Handle counter stuff */
 	for (i = 0; i < replace->selected_chain; i++) {
-		if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+		if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 			continue;
 		j = ebt_nr_to_chain(replace, i)->nentries;
 		while (j) {
@@ -737,11 +731,11 @@
 	if (cc && cc->type == CNT_DEL)
 		cc->type = CNT_OWRITE;
 	else {
-		new_cc = (struct ebt_cntchanges *)
-			 malloc(sizeof(struct ebt_cntchanges));
+		new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
 		if (!new_cc)
 			ebt_print_memory();
 		new_cc->type = CNT_ADD;
+		new_cc->change = 0;
 		new_cc->next = cc;
 		*prev_cc = new_cc;
 	}
@@ -780,6 +774,8 @@
 	}
 }
 
+/* If *begin==*end==0 then find the rule corresponding to new_entry,
+ * else make the rule numbers positive and check for bad rule numbers. */
 static int check_and_change_rule_number(struct ebt_u_replace *replace,
    struct ebt_u_entry *new_entry, int *begin, int *end)
 {
@@ -837,7 +833,7 @@
 
 	/* Handle counter stuff */
 	for (i = 0; i < replace->selected_chain; i++) {
-		if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+		if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 			continue;
 		j = ebt_nr_to_chain(replace, i)->nentries;
 		while (j) {
@@ -899,17 +895,19 @@
 	}
 }
 
-#define OPT_CNT_INCR	0x2000 /* This value is also defined in ebtables.c */
-#define OPT_CNT_DECR	0x4000 /* This value is also defined in ebtables.c */
 /* Change the counters of a rule or rules
  * begin == end == 0: change counters of the rule corresponding to new_entry
  *
  * The first rule has rule nr 1, the last rule has rule nr -1, etc.
  * This function expects the ebt_{match,watcher,target} members of new_entry
- * to contain pointers to ebt_u_{match,watcher,target}. */
+ * to contain pointers to ebt_u_{match,watcher,target}.
+ * The mask denotes the following:
+ *    pcnt: mask % 3 = 0 : change; = 1: increment; = 2: decrement
+ *    bcnt: mask / 3 = 0 : change; = 1: increment = 2: increment
+ * In daemon mode, mask==0 must hold */
 void ebt_change_counters(struct ebt_u_replace *replace,
 		     struct ebt_u_entry *new_entry, int begin, int end,
-		     struct ebt_counter *cnt)
+		     struct ebt_counter *cnt, int mask)
 {
 	int i, j;
 	struct ebt_u_entry *u_e;
@@ -920,7 +918,7 @@
 		return;
 
 	for (i = 0; i < replace->selected_chain; i++) {
-		if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+		if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 			continue;
 		j = ebt_nr_to_chain(replace, i)->nentries;
 		while (j) {
@@ -942,40 +940,34 @@
 	while (i) {
 		if (cc->type != CNT_DEL) {
 			i--;
-			if (cc->type != CNT_ADD && cc->type != CNT_OWRITE) {
-				/* In daemon mode, we want to make sure we don't lose
-				 * any counted packets/bytes (the kernel is still counting
-				 * while we are changing things in userspace). Therefore,
-				 * we need to add the amount to the counters in the kernel,
-				 * not the counters copied earlier from the kernel. */
-				u_e->cnt_surplus = *cnt;
-				if (replace->flags & OPT_CNT_INCR) {
-					cc->type = CNT_INCR;
-				} else if (replace->flags & OPT_CNT_DECR)
-					cc->type = CNT_DECR;
-				else {
-					cc->type = CNT_CHANGE;
-					u_e->cnt = *cnt;
-					u_e->cnt_surplus.pcnt = u_e->cnt_surplus.bcnt = 0;
-				}
-			} else { /* A -C after a -A remains a -A */
-				if (replace->flags & OPT_CNT_INCR) {
-					u_e->cnt.pcnt += cnt->pcnt;
-					u_e->cnt.bcnt += cnt->bcnt;
-				} else if (replace->flags & OPT_CNT_DECR) {
-					u_e->cnt.pcnt -= cnt->pcnt;
-					u_e->cnt.bcnt -= cnt->bcnt;
-				} else
-					u_e->cnt = *cnt;
+			if (mask % 3 == 0) {
+				u_e->cnt.pcnt = (*cnt).pcnt;
+				u_e->cnt_surplus.pcnt = 0;
+			} else {
+				if (cc->type != CNT_NORM)
+					ebt_print_bug("cc->type != CNT_NORM");
+				u_e->cnt_surplus.pcnt = (*cnt).pcnt;
 			}
+
+			if (mask / 3 == 0) {
+				u_e->cnt.bcnt = (*cnt).bcnt;
+				u_e->cnt_surplus.bcnt = 0;
+			} else {
+				if (cc->type != CNT_NORM)
+					ebt_print_bug("cc->type != CNT_NORM");
+				u_e->cnt_surplus.bcnt = (*cnt).bcnt;
+			}
+			if (cc->type == CNT_NORM || cc->type == CNT_ZERO)
+				cc->type = CNT_CHANGE;
+			cc->change = mask;
 			u_e = u_e->next;
 		}
 		cc = cc->next;
 	}
 }
 
-/* Selected_chain == -1 : zero all counters
- * Otherwise, zero the counters of selected_chain */
+/* If selected_chain == -1 then zero all counters,
+ * otherwise, zero the counters of selected_chain */
 void ebt_zero_counters(struct ebt_u_replace *replace)
 {
 	struct ebt_u_entries *entries = ebt_to_chain(replace);
@@ -992,7 +984,7 @@
 		i = -1;
 		while (1) {
 			i++;
-			if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+			if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 				continue;
 			entries = ebt_nr_to_chain(replace, i);
 			if (!entries) {
@@ -1006,14 +998,13 @@
 				next = next->next;
 			}
 		}
-			
 	} else {
 		next = entries->entries;
 		if (entries->nentries == 0)
 			return;
 
 		for (i = 0; i < replace->selected_chain; i++) {
-			if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+			if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 				continue;
 			j = ebt_nr_to_chain(replace, i)->nentries;
 			while (j) {
@@ -1059,8 +1050,7 @@
 	if (!cl)
 		ebt_print_memory();
 	cl->next = NULL;
-	cl->udc = (struct ebt_u_entries *)
-	   malloc(sizeof(struct ebt_u_entries));
+	cl->udc = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
 	if (!cl->udc)
 		ebt_print_memory();
 	cl->udc->nentries = 0;
@@ -1217,7 +1207,7 @@
 	/* Initialize hook_mask to 0 */
 	while (1) {
 		i++;
-		if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+		if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i]))
 			continue;
 		entries = ebt_nr_to_chain(replace, i);
 		if (!entries)
@@ -1225,15 +1215,14 @@
 		entries->hook_mask = 0;
 	}
 	if (i > NF_BR_NUMHOOKS) {
-		stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
-		   sizeof(struct ebt_u_stack));
+		stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) * sizeof(struct ebt_u_stack));
 		if (!stack)
 			ebt_print_memory();
 	}
 
 	/* Check for loops, starting from every base chain */
 	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-		if (!(replace->valid_hooks & (1 << i)))
+		if (!(replace->hook_entry[i]))
 			continue;
 		entries = ebt_nr_to_chain(replace, i);
 		/* (1 << NF_BR_NUMHOOKS) implies it's a standard chain