xref: /openbmc/sdeventplus/example/follow.cpp (revision a8c11e3c)
1 #include <fcntl.h>
2 #include <signal.h>
3 #include <sys/epoll.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 
8 #include <sdeventplus/event.hpp>
9 #include <sdeventplus/source/event.hpp>
10 #include <sdeventplus/source/io.hpp>
11 #include <sdeventplus/source/signal.hpp>
12 
13 #include <cerrno>
14 #include <cstdio>
15 #include <cstring>
16 #include <exception>
17 #include <functional>
18 
reader(const char * fifo,sdeventplus::source::IO & source,int fd,uint32_t)19 void reader(const char* fifo, sdeventplus::source::IO& source, int fd, uint32_t)
20 {
21     char buf[4096];
22     ssize_t r = read(fd, buf, sizeof(buf));
23     if (r == 0)
24     {
25         int newfd = open(fifo, O_NONBLOCK | O_RDONLY);
26         if (newfd < 0)
27         {
28             fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
29             source.get_event().exit(1);
30             return;
31         }
32         source.set_fd(newfd);
33         if (close(fd))
34         {
35             fprintf(stderr, "Failed to close fd\n");
36             source.get_event().exit(1);
37             return;
38         }
39         return;
40     }
41     if (r < 0)
42     {
43         fprintf(stderr, "Reader error: %s\n", strerror(errno));
44         source.get_event().exit(1);
45         return;
46     }
47     printf("%.*s", static_cast<int>(r), buf);
48 }
49 
remover(const char * fifo,sdeventplus::source::EventBase & source)50 void remover(const char* fifo, sdeventplus::source::EventBase& source)
51 {
52     int r = unlink(fifo);
53     if (r)
54     {
55         fprintf(stderr, "Failed to remove fifo %s: %s\n", fifo,
56                 strerror(errno));
57         source.get_event().exit(1);
58     }
59 }
60 
clean_exit(sdeventplus::source::Signal & source,const struct signalfd_siginfo *)61 void clean_exit(sdeventplus::source::Signal& source,
62                 const struct signalfd_siginfo*)
63 {
64     source.get_event().exit(0);
65 }
66 
main(int argc,char * argv[])67 int main(int argc, char* argv[])
68 {
69     if (argc != 2)
70     {
71         fprintf(stderr, "Usage: %s [named pipe to create]\n", argv[0]);
72         return 1;
73     }
74     const char* fifo = argv[1];
75 
76     // Block all signals before changing system state so we guarantee our clean
77     // up routines are in place
78     sigset_t signals;
79     if (sigfillset(&signals))
80     {
81         fprintf(stderr, "Failed to populate signals: %s\n", strerror(errno));
82         return 1;
83     }
84     if (sigprocmask(SIG_BLOCK, &signals, nullptr))
85     {
86         fprintf(stderr, "Failed to mask signals: %s\n", strerror(errno));
87         return 1;
88     }
89 
90     if (mkfifo(fifo, 0622))
91     {
92         fprintf(stderr, "Failed to mkfifo %s: %s\n", fifo, strerror(errno));
93         return 1;
94     }
95 
96     int fd = open(fifo, O_NONBLOCK | O_RDONLY);
97     if (fd < 0)
98     {
99         fprintf(stderr, "Failed to open %s: %s\n", fifo, strerror(errno));
100         return 1;
101     }
102 
103     try
104     {
105         sdeventplus::Event event = sdeventplus::Event::get_default();
106         sdeventplus::source::Exit remover_source(
107             event, std::bind(remover, fifo, std::placeholders::_1));
108         sdeventplus::source::Signal sigint(event, SIGINT, clean_exit);
109         sdeventplus::source::IO reader_source(
110             event, fd, EPOLLIN,
111             std::bind(reader, fifo, std::placeholders::_1,
112                       std::placeholders::_2, std::placeholders::_3));
113         return event.loop();
114     }
115     catch (const std::exception& e)
116     {
117         fprintf(stderr, "%s\n", e.what());
118         return 1;
119     }
120 }
121