example/follow: Implement
diff --git a/example/follow.cpp b/example/follow.cpp
index 36cd44b..7f72687 100644
--- a/example/follow.cpp
+++ b/example/follow.cpp
@@ -1,14 +1,118 @@
+#include <cerrno>
 #include <cstdio>
+#include <cstring>
+#include <exception>
+#include <fcntl.h>
+#include <functional>
 #include <sdeventplus/event.hpp>
+#include <sdeventplus/source/event.hpp>
+#include <sdeventplus/source/io.hpp>
+#include <sdeventplus/source/signal.hpp>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+void reader(const char* fifo, sdeventplus::source::IO& source, int fd, uint32_t)
+{
+    char buf[4096];
+    ssize_t r = read(fd, buf, sizeof(buf));
+    if (r == 0)
+    {
+        int newfd = open(fifo, O_NONBLOCK | O_RDONLY);
+        if (newfd < 0)
+        {
+            fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
+            source.get_event().exit(1);
+            return;
+        }
+        source.set_fd(newfd);
+        if (close(fd))
+        {
+            fprintf(stderr, "Failed to close fd\n");
+            source.get_event().exit(1);
+            return;
+        }
+        return;
+    }
+    if (r < 0)
+    {
+        fprintf(stderr, "Reader error: %s\n", strerror(errno));
+        source.get_event().exit(1);
+        return;
+    }
+    printf("%.*s", static_cast<int>(r), buf);
+}
+
+void remover(const char* fifo, sdeventplus::source::EventBase& source)
+{
+    int r = unlink(fifo);
+    if (r)
+    {
+        fprintf(stderr, "Failed to remove fifo %s: %s\n", fifo,
+                strerror(errno));
+        source.get_event().exit(1);
+    }
+}
+
+void clean_exit(sdeventplus::source::Signal& source,
+                const struct signalfd_siginfo*)
+{
+    source.get_event().exit(0);
+}
 
 int main(int argc, char* argv[])
 {
     if (argc != 2)
     {
-        fprintf(stderr, "Usage: %s [file]\n", argv[0]);
+        fprintf(stderr, "Usage: %s [named pipe to create]\n", argv[0]);
+        return 1;
+    }
+    const char* fifo = argv[1];
+
+    // Block all signals before changing system state so we guarantee our clean
+    // up routines are in place
+    sigset_t signals;
+    if (sigfillset(&signals))
+    {
+        fprintf(stderr, "Failed to populate signals: %s\n", strerror(errno));
+        return 1;
+    }
+    if (sigprocmask(SIG_BLOCK, &signals, nullptr))
+    {
+        fprintf(stderr, "Failed to mask signals: %s\n", strerror(errno));
         return 1;
     }
 
-    sdeventplus::Event event = sdeventplus::Event::get_default();
-    return event.loop();
+    if (mkfifo(fifo, 0622))
+    {
+        fprintf(stderr, "Failed to mkfifo %s: %s\n", fifo, strerror(errno));
+        return 1;
+    }
+
+    int fd = open(fifo, O_NONBLOCK | O_RDONLY);
+    if (fd < 0)
+    {
+        fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
+        return 1;
+    }
+
+    try
+    {
+        sdeventplus::Event event = sdeventplus::Event::get_default();
+        sdeventplus::source::Exit remover_source(
+            event, std::bind(remover, fifo, std::placeholders::_1));
+        sdeventplus::source::Signal sigint(event, SIGINT, clean_exit);
+        sdeventplus::source::IO reader_source(
+            event, fd, EPOLLIN,
+            std::bind(reader, fifo, std::placeholders::_1,
+                      std::placeholders::_2, std::placeholders::_3));
+        return event.loop();
+    }
+    catch (const std::exception& e)
+    {
+        fprintf(stderr, "%s\n", e.what());
+        return 1;
+    }
 }