So I believe there's a (little) bug in ftrigr_update(). It has multiple
symptoms, but basically it boils down to: the list of ids
"returned"/made available can sometimes contain duplicates, and also
the return value might be wrong.

Imagine this: I subscribe w/ regex "[abc]" and option FTRIGR_REPEAT, and
then events a & c occur in that order.

Now, when calling ftrigr_update() what does it return? If you answered
2 you are correct, but that's also not what it should be. As per the
doc, it should return "the number of identifiers for which something
happened" -- which cannot possibly be more than 1 when there is only
one id being used so far!
(Currently it actually returns the number of messages received from the
daemon, if I'm not mistaken.)

Never mind that return value, I get the id from the list & call
ftrigr_check() for it. As expected it tells me the last event was 'c'
and it returns 2, aka the number of times it was triggered (p->count).

I process this however I need, and all is good... Except, as you
(probaly) guessed, there's another id in the list. Or, more accurately,
the same id a second time.

Save for errors, ftrigr_update() should return the number of ids for
which something happened, as the doc says, i.e. the length of the list
of ids. 
So this is what the attached patch does.

>From 83c085e350fe2752b8ebc8f85fbff3556bd55c49 Mon Sep 17 00:00:00 2001
From: Olivier Brunel <j...@jjacky.com>
Date: Fri, 27 Jan 2017 18:55:18 +0100
Subject: [PATCH] ftrigr_update: ensure there's no duplicate ids

Also do indeed return the number of ids for which something happened
(instead of the number of messages received).

Signed-off-by: Olivier Brunel <j...@jjacky.com>
 src/libs6/ftrigr_update.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/libs6/ftrigr_update.c b/src/libs6/ftrigr_update.c
index ad69714..182d459 100644
--- a/src/libs6/ftrigr_update.c
+++ b/src/libs6/ftrigr_update.c
@@ -9,6 +9,12 @@
 #include <skalibs/skaclient.h>
 #include <s6/ftrigr.h>
+static inline int is_in_list (uint16 id, uint16 *list, unsigned int len)
+    while (len) if (list[--len] == id) return 1 ;
+    return 0 ;
 static int msghandler (unixmessage_t const *m, void *context)
   ftrigr_t *a = (ftrigr_t *)context ;
@@ -32,12 +38,18 @@ static int msghandler (unixmessage_t const *m, void *context)
     default : return (errno = EPROTO, 0) ;
   p->what = m->s[3] ;
-  id++ ; genalloc_append(uint16, &a->list, &id) ;
+  if (p->state != FR1STATE_LISTENING || p->count == 1
+          || !is_in_list(id+1, genalloc_s(uint16, &a->list),
+                         genalloc_len(uint16, &a->list))) {
+    id++ ; genalloc_append(uint16, &a->list, &id) ;
+  }
   return 1 ;
 int ftrigr_update (ftrigr_t *a)
+  int r ;
   genalloc_setlen(uint16, &a->list, 0) ;
-  return skaclient_update(&a->connection, &msghandler, a) ;
+  r = skaclient_update(&a->connection, &msghandler, a) ;
+  return (r < 0) ? r : genalloc_len(uint16, &a->list) ;

Reply via email to