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